Merge branch 'master' into autodoc
diff --git a/.gitignore b/.gitignore
index 7b60bb0..288f2ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,6 @@
 *.pyo
 __pycache__
 .tox
+doc/_build/
+.coverage
+.eggs
diff --git a/.travis.yml b/.travis.yml
index f359de1..c244622 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,83 +1,99 @@
+sudo: false
 language: python
 
-os:
-  - linux
-
-python:
-  - "pypy"
-  - "2.6"
-  - "2.7"
-  - "3.2"
-  - "3.3"
-  - "3.4"
-
 matrix:
   include:
+  - language: generic
+    os: osx
+    env: TOXENV=py27
+  - python: "2.6" # these are just to make travis's UI a bit prettier
+    env: TOXENV=py26
+  - python: "2.7"
+    env: TOXENV=py27
+  - python: "3.2"
+    env: TOXENV=py32
+  - python: "3.3"
+    env: TOXENV=py33
+  - python: "3.4"
+    env: TOXENV=py34
+  - python: "pypy"
+    env: TOXENV=pypy
   # Also run the tests against cryptography master.
   - python: "2.6"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py26
   - python: "2.7"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py27
   - python: "3.2"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py32
   - python: "3.3"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py33
   - python: "3.4"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py34
   - python: "pypy"
     env:
-      CRYPTOGRAPHY_GIT_MASTER=true
+      CRYPTOGRAPHY_GIT_MASTER=true TOXENV=pypy
 
   # Also run at least a little bit against an older version of OpenSSL.
   - python: "2.7"
     env:
-      OPENSSL=0.9.8
+      OPENSSL=0.9.8 TOXENV=py27
+    addons:
+      apt:
+        sources:
+          - lucid
+        packages:
+          - libssl-dev/lucid
 
   # Let the cryptography master builds fail because they might be triggered by
   # cryptography changes beyond our control.
+  # Also allow OS X and 0.9.8 to fail at the moment while we fix these new
+  # build configurations.
   allow_failures:
-  - env:
-      CRYPTOGRAPHY_GIT_MASTER=true
-  - env:
-      OPENSSL=0.9.8
+  - language: generic
+    os: osx
+    env: TOXENV=py27
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py26
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py27
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py32
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py33
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=py34
+  - env: CRYPTOGRAPHY_GIT_MASTER=true TOXENV=pypy
+  - env: OPENSSL=0.9.8 TOXENV=py27
 
 before_install:
   - if [ -n "$CRYPTOGRAPHY_GIT_MASTER" ]; then pip install git+https://github.com/pyca/cryptography.git;fi
 
 install:
-  # Install the wheel library explicitly here.  It is not really a setup
-  # dependency.  It is not an install dependency.  It is only a dependency for
-  # the script directive below - because we want to exercise wheel building on
-  # travis.
-  - pip install wheel
-
-  # Also install some tools for measuring code coverage and sending the results
-  # to coveralls.
-  - pip install coveralls coverage
+  - |
+    if [[ "$(uname -s)" == 'Darwin' ]]; then
+      brew update
+      brew upgrade openssl
+      curl -O https://bootstrap.pypa.io/get-pip.py
+      python get-pip.py --user
+      pip install --user virtualenv
+    else
+      pip install virtualenv
+    fi
+    python -m virtualenv ~/.venv
+    ~/.venv/bin/pip install coveralls tox
 
 script:
   - |
-    if [[ "${OPENSSL}" == "0.9.8" ]]; then
-      sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ lucid main"
-      sudo apt-get -y update
-      sudo apt-get install -y --force-yes libssl-dev/lucid
+    if [[ "$(uname -s)" == "Darwin" ]]; then
+      # set our flags to use homebrew openssl
+      export ARCHFLAGS="-arch x86_64"
+      export LDFLAGS="-L/usr/local/opt/openssl/lib"
+      export CFLAGS="-I/usr/local/opt/openssl/include"
     fi
-  - |
-    pip install -e .
-  - |
-    coverage run --branch --source=OpenSSL setup.py bdist_wheel test
-  - |
-    coverage report -m
-  - |
-    python -c "import OpenSSL.SSL; print(OpenSSL.SSL.SSLeay_version(OpenSSL.SSL.SSLEAY_VERSION))"
+    ~/.venv/bin/tox
 
-after_success:
-    - coveralls
+after_script:
+  - ~/.venv/bin/coveralls
 
 notifications:
   email: false
diff --git a/ChangeLog b/ChangeLog
index 9ad9317..61bfa5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,66 @@
+2015-04-15  Paul Kehrer <paul.l.kehrer@gmail.com>
+
+	* OpenSSL/crypto.py, OpenSSL/test/test_crypto.py: Switch to utf8string
+	  mask by default. OpenSSL formerly defaulted to a T61String if there
+	  were UTF-8 characters present.  This was changed to default to
+	  UTF8String in the config around 2005, but the actual code didn't
+	  change it until late last year. This will default us to the setting
+	  that actually works. To revert this you can call
+	  crypto._lib.ASN1_STRING_set_default_mask_asc(b"default")
+
+2015-04-14  Hynek Schlawack  <hs@ox.cx>
+
+	* Release 0.15.1
+
+2015-04-14  Glyph Lefkowitz  <glyph@twistedmatrix.com>
+
+	* OpenSSL/SSL.py, OpenSSL/test/test_ssl.py: Fix a regression
+	  present in 0.15, where when an error occurs and no errno() is set,
+	  a KeyError is raised.  This happens, for example, if
+	  Connection.shutdown() is called when the underlying transport has
+	  gone away.
+
+2011-09-02  Hynek Schlawack  <hs@ox.cx>
+
+	* Release 0.15
+
+2015-04-12  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* OpenSSL/rand.py, OpenSSL/SSL.py: APIs which previously accepted
+	  filenames only as bytes now accept them as either bytes or
+	  unicode (and respect sys.getfilesystemencoding()).
+
+2015-03-23  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* OpenSSL/SSL.py: Add Cory Benfield's next-protocol-negotiation
+	  (NPN) bindings.
+
+2015-03-15  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* OpenSSL/SSL.py: Add ``Connection.recv_into``, mirroring the
+	  builtin ``socket.recv_into``.  Based on work from Cory Benfield.
+	* OpenSSL/test/test_ssl.py: Add tests for ``recv_into``.
+
+2015-01-30  Stephen Holsapple <sholsapp@gmail.com>
+
+	* OpenSSL/crypto.py: Expose ``X509StoreContext`` for verifying certificates.
+	* OpenSSL/test/test_crypto.py: Add intermediate certificates for
+
+2015-01-08  Paul Aurich <paul@darkrain42.org>
+
+	* OpenSSL/SSL.py: ``Connection.shutdown`` now propagates errors from the
+	  underlying socket.
+
+2014-12-11  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* OpenSSL/SSL.py: Fixed a regression ``Context.check_privatekey``
+	  causing it to always succeed - even if it should fail.
+
+2014-08-21  Alex Gaynor  <alex.gaynor@gmail.com>
+
+	* OpenSSL/crypto.py: Fixed a regression where calling ``load_pkcs7_data``
+	  with ``FILETYPE_ASN1`` would fail with a ``NameError``.
+
 2014-05-05  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* OpenSSL/SSL.py: Fix a regression in which the first argument of
@@ -55,6 +118,10 @@
 
 	* OpenSSL/crypto.py: Add ``get_extensions`` method to ``X509Req``.
 
+2014-02-23  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* Release 0.14
+
 2014-01-09  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* OpenSSL: Port to the cffi-based OpenSSL bindings provided by
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 3af722f..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,33 +0,0 @@
-Installation
-------------
-pyOpenSSL uses distutils.  Use setup.py to install it in the usual way:
-
-  $ python setup.py install --user
-
-Or use pip:
-
-  $ pip install --user .
-
-You can, of course, do
-
-  $ python setup.py --help
-
-or
-
-  $ pip install --help
-
-to find out more about how to use these tools.
-
-Documentation
--------------
-
-The documentation is written in reStructuredText and build using Sphinx.
-
-To build the text, html, postscript or dvi forms of the documentation, this is
-what you do:
-
-    cd doc
-    # To make the text-only documentation:
-    make text
-    # To make the dvi form:
-    make dvi
diff --git a/INSTALL.rst b/INSTALL.rst
new file mode 100644
index 0000000..eea013b
--- /dev/null
+++ b/INSTALL.rst
@@ -0,0 +1,19 @@
+Installation
+============
+
+To install pyOpenSSL::
+
+  $ pip install pyopenssl
+
+If you are installing in order to *develop* on pyOpenSSL, move to the root directory of a pyOpenSSL checkout, and run::
+
+  $ pip install -e .
+
+
+Documentation
+=============
+
+The documentation is written in reStructuredText and built using Sphinx::
+
+  $ cd doc
+  $ make html
diff --git a/MANIFEST.in b/MANIFEST.in
index 8137258..455af6d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,8 @@
-include     LICENSE ChangeLog INSTALL README TODO MANIFEST.in OpenSSL/RATIONALE
+include     LICENSE ChangeLog TODO MANIFEST.in OpenSSL/RATIONALE *.rst tox.ini memdbg.py runtests.py OpenSSL/test/README
+exclude leakcheck
 recursive-include   doc         *
 recursive-include   examples    *
 recursive-include   rpm         *
+recursive-exclude   leakcheck   *.py *.pem
 global-exclude  *.pyc
 prune               doc/_build
diff --git a/OpenSSL/RATIONALE b/OpenSSL/RATIONALE
deleted file mode 100644
index a0e389c..0000000
--- a/OpenSSL/RATIONALE
+++ /dev/null
@@ -1,61 +0,0 @@
-  RATIONALE
-
-The reason this module exists at all is that the SSL support in the socket
-module in the Python 2.1 distribution (which is what we used, of course I
-cannot speak for later versions) is severely limited.
-
-<FIXME> Update this list whenever needed! The communications module isn't
-written yet, so we don't know exactly how this'll work! </FIXME>
-This is a list of things we need from an OpenSSL module:
- + Context objects (in OpenSSL called SSL_CTX) that can be manipulated from
-   Python modules.  They must support a number of operations:
-     - Loading certificates from file and memory, both the client
-       certificate and the certificates used for the verification chain.
-     - Loading private keys from file and memory.
-     - Setting the verification mode (basically VERIFY_NONE and
-       VERIFY_PEER).
-     - Callbacks mechanism for prompting for pass phrases and verifying
-       certificates.  The callbacks have to work under a multi-threaded
-       environment (see the comment in ssl/context.c).  Of course the
-       callbacks will have to be written in Python!
- + The Connection objects (in OpenSSL called SSL) have to support a few
-   things:
-     - Renegotiation, this is really important, especially for connections
-       that are up and running for a long time, since renegotiation
-       generates new encryption keys.
-     - Server-side SSL must work!  As far as I know this doesn't work in
-       the SSL support of the socket module as of Python 2.1.
-     - Wrapping the methods of the underlying transport object is nice, so
-       you don't have to keep track of more than one object per connection.
-       This could of course be done a lot better than the way it works now,
-       so more transport layers than sockets are possible!
- + A well-organized error system that mimics OpenSSL's error system is
-   desireable.  Specifically there has to be a way to find out wether the
-   operation was successful, or if it failed, why it failed, so some sort
-   of interface to OpenSSL's error queue mechanism is needed.
- + Certificate objects (X509) and certificate name objects (X509_NAME) are
-   needed, especially for verification purposes.  Certificates will
-   probably also be generated by the server which is another reason for
-   them to exist. The same thing goes for key objects (EVP_PKEY)
- + Since this is an OpenSSL module, there has to be an interface to the
-   OpenSSL PRNG, so it can be seeded in a good way.
-
-When asking about SSL on the comp.lang.python newsgroup (or on
-python-list@python.org) people usually pointed you to the M2Crypto package.
-The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but
-unfortunately its error handling system does not seem to be finished,
-especially for non-blocking I/O.  I think that much of the reason for this
-is that M2Crypto is developed using SWIG.  This makes it awkward to create
-functions that e.g. can return both an integer and NULL since (as far as I
-know) you basically write C functions and SWIG makes wrapper functions that
-parses the Python argument list and calls your C function, and finally
-transforms your return value to a Python object.
-
-Finally, a good book on the topic of SSL (that I read and learned a lot
-from) is "SSL and TLS - Designing and Building Secure Systems" (ISBN
-0201615983) by Eric Rescorla. A good mailinglist to subscribe to is the
-openssl-users@openssl.org list.
-
-This comment was written July 2001, discussing Python 2.1.  Feel free to
-modify it as the SSL support in the socket module changes.
-
diff --git a/OpenSSL/SSL.py b/OpenSSL/SSL.py
index 7b1cbc1..e67bd13 100644
--- a/OpenSSL/SSL.py
+++ b/OpenSSL/SSL.py
@@ -1,23 +1,27 @@
 from sys import platform
 from functools import wraps, partial
-from itertools import count
+from itertools import count, chain
 from weakref import WeakValueDictionary
 from errno import errorcode
 
 from six import text_type as _text_type
+from six import binary_type as _binary_type
 from six import integer_types as integer_types
+from six import int2byte, indexbytes
 
 from OpenSSL._util import (
     ffi as _ffi,
     lib as _lib,
     exception_from_error_queue as _exception_from_error_queue,
-    native as _native)
+    native as _native,
+    text_to_bytes_and_warn as _text_to_bytes_and_warn,
+    path_string as _path_string,
+    UNSPECIFIED as _UNSPECIFIED,
+)
 
 from OpenSSL.crypto import (
     FILETYPE_PEM, _PassphraseHelper, PKey, X509Name, X509, X509Store)
 
-_unspecified = object()
-
 try:
     _memoryview = memoryview
 except NameError:
@@ -164,11 +168,42 @@
     pass
 
 
+class _CallbackExceptionHelper(object):
+    """
+    A base class for wrapper classes that allow for intelligent exception
+    handling in OpenSSL callbacks.
 
-class _VerifyHelper(object):
-    def __init__(self, callback):
+    :ivar list _problems: Any exceptions that occurred while executing in a
+        context where they could not be raised in the normal way.  Typically
+        this is because OpenSSL has called into some Python code and requires a
+        return value.  The exceptions are saved to be raised later when it is
+        possible to do so.
+    """
+    def __init__(self):
         self._problems = []
 
+
+    def raise_if_problem(self):
+        """
+        Raise an exception from the OpenSSL error queue or that was previously
+        captured whe running a callback.
+        """
+        if self._problems:
+            try:
+                _raise_current_error()
+            except Error:
+                pass
+            raise self._problems.pop(0)
+
+
+class _VerifyHelper(_CallbackExceptionHelper):
+    """
+    Wrap a callback such that it can be used as a certificate verification
+    callback.
+    """
+    def __init__(self, callback):
+        _CallbackExceptionHelper.__init__(self)
+
         @wraps(callback)
         def wrapper(ok, store_ctx):
             cert = X509.__new__(X509)
@@ -196,14 +231,142 @@
             "int (*)(int, X509_STORE_CTX *)", wrapper)
 
 
-    def raise_if_problem(self):
-        if self._problems:
-            try:
-                _raise_current_error()
-            except Error:
-                pass
-            raise self._problems.pop(0)
+class _NpnAdvertiseHelper(_CallbackExceptionHelper):
+    """
+    Wrap a callback such that it can be used as an NPN advertisement callback.
+    """
+    def __init__(self, callback):
+        _CallbackExceptionHelper.__init__(self)
 
+        @wraps(callback)
+        def wrapper(ssl, out, outlen, arg):
+            try:
+                conn = Connection._reverse_mapping[ssl]
+                protos = callback(conn)
+
+                # Join the protocols into a Python bytestring, length-prefixing
+                # each element.
+                protostr = b''.join(
+                    chain.from_iterable((int2byte(len(p)), p) for p in protos)
+                )
+
+                # Save our callback arguments on the connection object. This is
+                # done to make sure that they don't get freed before OpenSSL
+                # uses them. Then, return them appropriately in the output
+                # parameters.
+                conn._npn_advertise_callback_args = [
+                    _ffi.new("unsigned int *", len(protostr)),
+                    _ffi.new("unsigned char[]", protostr),
+                ]
+                outlen[0] = conn._npn_advertise_callback_args[0][0]
+                out[0] = conn._npn_advertise_callback_args[1]
+                return 0
+            except Exception as e:
+                self._problems.append(e)
+                return 2  # SSL_TLSEXT_ERR_ALERT_FATAL
+
+        self.callback = _ffi.callback(
+            "int (*)(SSL *, const unsigned char **, unsigned int *, void *)",
+            wrapper
+        )
+
+
+class _NpnSelectHelper(_CallbackExceptionHelper):
+    """
+    Wrap a callback such that it can be used as an NPN selection callback.
+    """
+    def __init__(self, callback):
+        _CallbackExceptionHelper.__init__(self)
+
+        @wraps(callback)
+        def wrapper(ssl, out, outlen, in_, inlen, arg):
+            try:
+                conn = Connection._reverse_mapping[ssl]
+
+                # The string passed to us is actually made up of multiple
+                # length-prefixed bytestrings. We need to split that into a
+                # list.
+                instr = _ffi.buffer(in_, inlen)[:]
+                protolist = []
+                while instr:
+                    l = indexbytes(instr, 0)
+                    proto = instr[1:l+1]
+                    protolist.append(proto)
+                    instr = instr[l+1:]
+
+                # Call the callback
+                outstr = callback(conn, protolist)
+
+                # Save our callback arguments on the connection object. This is
+                # done to make sure that they don't get freed before OpenSSL
+                # uses them. Then, return them appropriately in the output
+                # parameters.
+                conn._npn_select_callback_args = [
+                    _ffi.new("unsigned char *", len(outstr)),
+                    _ffi.new("unsigned char[]", outstr),
+                ]
+                outlen[0] = conn._npn_select_callback_args[0][0]
+                out[0] = conn._npn_select_callback_args[1]
+                return 0
+            except Exception as e:
+                self._problems.append(e)
+                return 2  # SSL_TLSEXT_ERR_ALERT_FATAL
+
+        self.callback = _ffi.callback(
+            "int (*)(SSL *, unsigned char **, unsigned char *, "
+                    "const unsigned char *, unsigned int, void *)",
+            wrapper
+        )
+
+
+class _ALPNSelectHelper(_CallbackExceptionHelper):
+    """
+    Wrap a callback such that it can be used as an ALPN selection callback.
+    """
+    def __init__(self, callback):
+        _CallbackExceptionHelper.__init__(self)
+
+        @wraps(callback)
+        def wrapper(ssl, out, outlen, in_, inlen, arg):
+            try:
+                conn = Connection._reverse_mapping[ssl]
+
+                # The string passed to us is made up of multiple
+                # length-prefixed bytestrings. We need to split that into a
+                # list.
+                instr = _ffi.buffer(in_, inlen)[:]
+                protolist = []
+                while instr:
+                    encoded_len = indexbytes(instr, 0)
+                    proto = instr[1:encoded_len + 1]
+                    protolist.append(proto)
+                    instr = instr[encoded_len + 1:]
+
+                # Call the callback
+                outstr = callback(conn, protolist)
+
+                if not isinstance(outstr, _binary_type):
+                    raise TypeError("ALPN callback must return a bytestring.")
+
+                # Save our callback arguments on the connection object to make
+                # sure that they don't get freed before OpenSSL can use them.
+                # Then, return them in the appropriate output parameters.
+                conn._alpn_select_callback_args = [
+                    _ffi.new("unsigned char *", len(outstr)),
+                    _ffi.new("unsigned char[]", outstr),
+                ]
+                outlen[0] = conn._alpn_select_callback_args[0][0]
+                out[0] = conn._alpn_select_callback_args[1]
+                return 0
+            except Exception as e:
+                self._problems.append(e)
+                return 2  # SSL_TLSEXT_ERR_ALERT_FATAL
+
+        self.callback = _ffi.callback(
+            "int (*)(SSL *, unsigned char **, unsigned char *, "
+                    "const unsigned char *, unsigned int, void *)",
+            wrapper
+        )
 
 
 def _asFileDescriptor(obj):
@@ -235,6 +398,37 @@
     return _ffi.string(_lib.SSLeay_version(type))
 
 
+def _requires_npn(func):
+    """
+    Wraps any function that requires NPN support in OpenSSL, ensuring that
+    NotImplementedError is raised if NPN is not present.
+    """
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        if not _lib.Cryptography_HAS_NEXTPROTONEG:
+            raise NotImplementedError("NPN not available.")
+
+        return func(*args, **kwargs)
+
+    return wrapper
+
+
+
+def _requires_alpn(func):
+    """
+    Wraps any function that requires ALPN support in OpenSSL, ensuring that
+    NotImplementedError is raised if ALPN support is not present.
+    """
+    @wraps(func)
+    def wrapper(*args, **kwargs):
+        if not _lib.Cryptography_HAS_ALPN:
+            raise NotImplementedError("ALPN not available.")
+
+        return func(*args, **kwargs)
+
+    return wrapper
+
+
 
 class Session(object):
     pass
@@ -293,6 +487,12 @@
         self._info_callback = None
         self._tlsext_servername_callback = None
         self._app_data = None
+        self._npn_advertise_helper = None
+        self._npn_advertise_callback = None
+        self._npn_select_helper = None
+        self._npn_select_callback = None
+        self._alpn_select_helper = None
+        self._alpn_select_callback = None
 
         # SSL_CTX_set_app_data(self->ctx, self);
         # SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
@@ -306,19 +506,22 @@
         Let SSL know where we can find trusted certificates for the certificate
         chain
 
-        :param cafile: In which file we can find the certificates
+        :param cafile: In which file we can find the certificates (``bytes`` or
+            ``unicode``).
         :param capath: In which directory we can find the certificates
+            (``bytes`` or ``unicode``).
+
         :return: None
         """
         if cafile is None:
             cafile = _ffi.NULL
-        elif not isinstance(cafile, bytes):
-            raise TypeError("cafile must be None or a byte string")
+        else:
+            cafile = _path_string(cafile)
 
         if capath is None:
             capath = _ffi.NULL
-        elif not isinstance(capath, bytes):
-            raise TypeError("capath must be None or a byte string")
+        else:
+            capath = _path_string(capath)
 
         load_result = _lib.SSL_CTX_load_verify_locations(self._context, cafile, capath)
         if not load_result:
@@ -368,15 +571,12 @@
         """
         Load a certificate chain from a file
 
-        :param certfile: The name of the certificate chain file
+        :param certfile: The name of the certificate chain file (``bytes`` or
+            ``unicode``).
+
         :return: None
         """
-        if isinstance(certfile, _text_type):
-            # Perhaps sys.getfilesystemencoding() could be better?
-            certfile = certfile.encode("utf-8")
-
-        if not isinstance(certfile, bytes):
-            raise TypeError("certfile must be bytes or unicode")
+        certfile = _path_string(certfile)
 
         result = _lib.SSL_CTX_use_certificate_chain_file(self._context, certfile)
         if not result:
@@ -387,15 +587,13 @@
         """
         Load a certificate from a file
 
-        :param certfile: The name of the certificate file
+        :param certfile: The name of the certificate file (``bytes`` or
+            ``unicode``).
         :param filetype: (optional) The encoding of the file, default is PEM
+
         :return: None
         """
-        if isinstance(certfile, _text_type):
-            # Perhaps sys.getfilesystemencoding() could be better?
-            certfile = certfile.encode("utf-8")
-        if not isinstance(certfile, bytes):
-            raise TypeError("certfile must be bytes or unicode")
+        certfile = _path_string(certfile)
         if not isinstance(filetype, integer_types):
             raise TypeError("filetype must be an integer")
 
@@ -445,22 +643,18 @@
             raise exception
 
 
-    def use_privatekey_file(self, keyfile, filetype=_unspecified):
+    def use_privatekey_file(self, keyfile, filetype=_UNSPECIFIED):
         """
         Load a private key from a file
 
-        :param keyfile: The name of the key file
+        :param keyfile: The name of the key file (``bytes`` or ``unicode``)
         :param filetype: (optional) The encoding of the file, default is PEM
+
         :return: None
         """
-        if isinstance(keyfile, _text_type):
-            # Perhaps sys.getfilesystemencoding() could be better?
-            keyfile = keyfile.encode("utf-8")
+        keyfile = _path_string(keyfile)
 
-        if not isinstance(keyfile, bytes):
-            raise TypeError("keyfile must be a byte string")
-
-        if filetype is _unspecified:
+        if filetype is _UNSPECIFIED:
             filetype = FILETYPE_PEM
         elif not isinstance(filetype, integer_types):
             raise TypeError("filetype must be an integer")
@@ -492,6 +686,9 @@
 
         :return: None (raises an exception if something's wrong)
         """
+        if not _lib.SSL_CTX_check_private_key(self._context):
+            _raise_current_error()
+
 
     def load_client_ca(self, cafile):
         """
@@ -591,11 +788,12 @@
         """
         Load parameters for Ephemeral Diffie-Hellman
 
-        :param dhfile: The file to load EDH parameters from
+        :param dhfile: The file to load EDH parameters from (``bytes`` or
+            ``unicode``).
+
         :return: None
         """
-        if not isinstance(dhfile, bytes):
-            raise TypeError("dhfile must be a byte string")
+        dhfile = _path_string(dhfile)
 
         bio = _lib.BIO_new_file(dhfile, b"r")
         if bio == _ffi.NULL:
@@ -809,6 +1007,79 @@
         _lib.SSL_CTX_set_tlsext_servername_callback(
             self._context, self._tlsext_servername_callback)
 
+
+    @_requires_npn
+    def set_npn_advertise_callback(self, callback):
+        """
+        Specify a callback function that will be called when offering `Next
+        Protocol Negotiation
+        <https://technotes.googlecode.com/git/nextprotoneg.html>`_ as a server.
+
+        :param callback: The callback function.  It will be invoked with one
+            argument, the Connection instance.  It should return a list of
+            bytestrings representing the advertised protocols, like
+            ``[b'http/1.1', b'spdy/2']``.
+        """
+        self._npn_advertise_helper = _NpnAdvertiseHelper(callback)
+        self._npn_advertise_callback = self._npn_advertise_helper.callback
+        _lib.SSL_CTX_set_next_protos_advertised_cb(
+            self._context, self._npn_advertise_callback, _ffi.NULL)
+
+
+    @_requires_npn
+    def set_npn_select_callback(self, callback):
+        """
+        Specify a callback function that will be called when a server offers
+        Next Protocol Negotiation options.
+
+        :param callback: The callback function.  It will be invoked with two
+            arguments: the Connection, and a list of offered protocols as
+            bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``.  It should return
+            one of those bytestrings, the chosen protocol.
+        """
+        self._npn_select_helper = _NpnSelectHelper(callback)
+        self._npn_select_callback = self._npn_select_helper.callback
+        _lib.SSL_CTX_set_next_proto_select_cb(
+            self._context, self._npn_select_callback, _ffi.NULL)
+
+    @_requires_alpn
+    def set_alpn_protos(self, protos):
+        """
+        Specify the clients ALPN protocol list.
+
+        These protocols are offered to the server during protocol negotiation.
+
+        :param protos: A list of the protocols to be offered to the server.
+            This list should be a Python list of bytestrings representing the
+            protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
+        """
+        # Take the list of protocols and join them together, prefixing them
+        # with their lengths.
+        protostr = b''.join(
+            chain.from_iterable((int2byte(len(p)), p) for p in protos)
+        )
+
+        # Build a C string from the list. We don't need to save this off
+        # because OpenSSL immediately copies the data out.
+        input_str = _ffi.new("unsigned char[]", protostr)
+        input_str_len = _ffi.cast("unsigned", len(protostr))
+        _lib.SSL_CTX_set_alpn_protos(self._context, input_str, input_str_len)
+
+    @_requires_alpn
+    def set_alpn_select_callback(self, callback):
+        """
+        Set the callback to handle ALPN protocol choice.
+
+        :param callback: The callback function.  It will be invoked with two
+            arguments: the Connection, and a list of offered protocols as
+            bytestrings, e.g ``[b'http/1.1', b'spdy/2']``.  It should return
+            one of those bytestrings, the chosen protocol.
+        """
+        self._alpn_select_helper = _ALPNSelectHelper(callback)
+        self._alpn_select_callback = self._alpn_select_helper.callback
+        _lib.SSL_CTX_set_alpn_select_cb(
+            self._context, self._alpn_select_callback, _ffi.NULL)
+
 ContextType = Context
 
 
@@ -833,6 +1104,19 @@
         self._ssl = _ffi.gc(ssl, _lib.SSL_free)
         self._context = context
 
+        # References to strings used for Next Protocol Negotiation. OpenSSL's
+        # header files suggest that these might get copied at some point, but
+        # doesn't specify when, so we store them here to make sure they don't
+        # get freed before OpenSSL uses them.
+        self._npn_advertise_callback_args = None
+        self._npn_select_callback_args = None
+
+        # References to strings used for Application Layer Protocol
+        # Negotiation. These strings get copied at some point but it's well
+        # after the callback returns, so we have to hang them somewhere to
+        # avoid them getting freed.
+        self._alpn_select_callback_args = None
+
         self._reverse_mapping[self._ssl] = self
 
         if socket is None:
@@ -867,6 +1151,12 @@
     def _raise_ssl_error(self, ssl, result):
         if self._context._verify_helper is not None:
             self._context._verify_helper.raise_if_problem()
+        if self._context._npn_advertise_helper is not None:
+            self._context._npn_advertise_helper.raise_if_problem()
+        if self._context._npn_select_helper is not None:
+            self._context._npn_select_helper.raise_if_problem()
+        if self._context._alpn_select_helper is not None:
+            self._context._alpn_select_helper.raise_if_problem()
 
         error = _lib.SSL_get_error(ssl, result)
         if error == _lib.SSL_ERROR_WANT_READ:
@@ -885,7 +1175,7 @@
                         errno = _ffi.getwinerror()[0]
                     else:
                         errno = _ffi.errno
-                    raise SysCallError(errno, errorcode[errno])
+                    raise SysCallError(errno, errorcode.get(errno))
                 else:
                     raise SysCallError(-1, "Unexpected EOF")
             else:
@@ -967,6 +1257,9 @@
                       API, the value is ignored
         :return: The number of bytes written
         """
+        # Backward compatibility
+        buf = _text_to_bytes_and_warn("buf", buf)
+
         if isinstance(buf, _memoryview):
             buf = buf.tobytes()
         if isinstance(buf, _buffer):
@@ -991,6 +1284,8 @@
                       API, the value is ignored
         :return: The number of bytes written
         """
+        buf = _text_to_bytes_and_warn("buf", buf)
+
         if isinstance(buf, _memoryview):
             buf = buf.tobytes()
         if isinstance(buf, _buffer):
@@ -1027,6 +1322,45 @@
     read = recv
 
 
+    def recv_into(self, buffer, nbytes=None, flags=None):
+        """
+        Receive data on the connection and store the data into a buffer rather
+        than creating a new string.
+
+        :param buffer: The buffer to copy into.
+        :param nbytes: (optional) The maximum number of bytes to read into the
+            buffer. If not present, defaults to the size of the buffer. If
+            larger than the size of the buffer, is reduced to the size of the
+            buffer.
+        :param flags: (optional) Included for compatibility with the socket
+            API, the value is ignored.
+        :return: The number of bytes read into the buffer.
+        """
+        if nbytes is None:
+            nbytes = len(buffer)
+        else:
+            nbytes = min(nbytes, len(buffer))
+
+        # We need to create a temporary buffer. This is annoying, it would be
+        # better if we could pass memoryviews straight into the SSL_read call,
+        # but right now we can't. Revisit this if CFFI gets that ability.
+        buf = _ffi.new("char[]", nbytes)
+        result = _lib.SSL_read(self._ssl, buf, nbytes)
+        self._raise_ssl_error(self._ssl, result)
+
+        # This strange line is all to avoid a memory copy. The buffer protocol
+        # should allow us to assign a CFFI buffer to the LHS of this line, but
+        # on CPython 3.3+ that segfaults. As a workaround, we can temporarily
+        # wrap it in a memoryview, except on Python 2.6 which doesn't have a
+        # memoryview type.
+        try:
+            buffer[:result] = memoryview(_ffi.buffer(buf, result))
+        except NameError:
+            buffer[:result] = _ffi.buffer(buf, result)
+
+        return result
+
+
     def _handle_bio_errors(self, bio, result):
         if _lib.BIO_should_retry(bio):
             if _lib.BIO_should_read(bio):
@@ -1076,12 +1410,11 @@
         :param buf: The string to put into the memory BIO.
         :return: The number of bytes written
         """
+        buf = _text_to_bytes_and_warn("buf", buf)
+
         if self._into_ssl is None:
             raise TypeError("Connection sock was not None")
 
-        if not isinstance(buf, bytes):
-            raise TypeError("buf must be a byte string")
-
         result = _lib.BIO_write(self._into_ssl, buf, len(buf))
         if result <= 0:
             self._handle_bio_errors(self._into_ssl, result)
@@ -1183,8 +1516,7 @@
         """
         result = _lib.SSL_shutdown(self._ssl)
         if result < 0:
-            # TODO: This is untested.
-            _raise_current_error()
+            self._raise_ssl_error(self._ssl, result)
         elif result > 0:
             return True
         else:
@@ -1551,6 +1883,61 @@
             return version.decode("utf-8")
 
 
+    @_requires_npn
+    def get_next_proto_negotiated(self):
+        """
+        Get the protocol that was negotiated by NPN.
+        """
+        data = _ffi.new("unsigned char **")
+        data_len = _ffi.new("unsigned int *")
+
+        _lib.SSL_get0_next_proto_negotiated(self._ssl, data, data_len)
+
+        return _ffi.buffer(data[0], data_len[0])[:]
+
+
+    @_requires_alpn
+    def set_alpn_protos(self, protos):
+        """
+        Specify the client's ALPN protocol list.
+
+        These protocols are offered to the server during protocol negotiation.
+
+        :param protos: A list of the protocols to be offered to the server.
+            This list should be a Python list of bytestrings representing the
+            protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
+        """
+        # Take the list of protocols and join them together, prefixing them
+        # with their lengths.
+        protostr = b''.join(
+            chain.from_iterable((int2byte(len(p)), p) for p in protos)
+        )
+
+        # Build a C string from the list. We don't need to save this off
+        # because OpenSSL immediately copies the data out.
+        input_str = _ffi.new("unsigned char[]", protostr)
+        input_str_len = _ffi.cast("unsigned", len(protostr))
+        _lib.SSL_set_alpn_protos(self._ssl, input_str, input_str_len)
+
+
+    def get_alpn_proto_negotiated(self):
+        """
+        Get the protocol that was negotiated by ALPN.
+        """
+        if not _lib.Cryptography_HAS_ALPN:
+            raise NotImplementedError("ALPN not available")
+
+        data = _ffi.new("unsigned char **")
+        data_len = _ffi.new("unsigned int *")
+
+        _lib.SSL_get0_alpn_selected(self._ssl, data, data_len)
+
+        if not data_len:
+            return b''
+
+        return _ffi.buffer(data[0], data_len[0])[:]
+
+
 
 ConnectionType = Connection
 
diff --git a/OpenSSL/_util.py b/OpenSSL/_util.py
index baeecc6..0cc34d8 100644
--- a/OpenSSL/_util.py
+++ b/OpenSSL/_util.py
@@ -1,3 +1,6 @@
+from warnings import warn
+import sys
+
 from six import PY3, binary_type, text_type
 
 from cryptography.hazmat.bindings.openssl.binding import Binding
@@ -5,11 +8,34 @@
 ffi = binding.ffi
 lib = binding.lib
 
-def exception_from_error_queue(exceptionType):
-    def text(charp):
-        return native(ffi.string(charp))
+
+
+def text(charp):
+    """
+    Get a native string type representing of the given CFFI ``char*`` object.
+
+    :param charp: A C-style string represented using CFFI.
+
+    :return: :class:`str`
+    """
+    if not charp:
+        return ""
+    return native(ffi.string(charp))
+
+
+
+def exception_from_error_queue(exception_type):
+    """
+    Convert an OpenSSL library failure into a Python exception.
+
+    When a call to the native OpenSSL library fails, this is usually signalled
+    by the return value, and an error code is stored in an error queue
+    associated with the current thread. The err library provides functions to
+    obtain these error codes and textual error messages.
+    """
 
     errors = []
+
     while True:
         error = lib.ERR_get_error()
         if error == 0:
@@ -19,7 +45,7 @@
                 text(lib.ERR_func_error_string(error)),
                 text(lib.ERR_reason_error_string(error))))
 
-    raise exceptionType(errors)
+    raise exception_type(errors)
 
 
 
@@ -45,9 +71,57 @@
 
 
 
+def path_string(s):
+    """
+    Convert a Python string to a :py:class:`bytes` string identifying the same
+    path and which can be passed into an OpenSSL API accepting a filename.
+
+    :param s: An instance of :py:class:`bytes` or :py:class:`unicode`.
+
+    :return: An instance of :py:class:`bytes`.
+    """
+    if isinstance(s, binary_type):
+        return s
+    elif isinstance(s, text_type):
+        return s.encode(sys.getfilesystemencoding())
+    else:
+        raise TypeError("Path must be represented as bytes or unicode string")
+
+
 if PY3:
     def byte_string(s):
         return s.encode("charmap")
 else:
     def byte_string(s):
         return s
+
+
+# A marker object to observe whether some optional arguments are passed any
+# value or not.
+UNSPECIFIED = object()
+
+_TEXT_WARNING = (
+    text_type.__name__ + " for {0} is no longer accepted, use bytes"
+)
+
+def text_to_bytes_and_warn(label, obj):
+    """
+    If ``obj`` is text, emit a warning that it should be bytes instead and try
+    to convert it to bytes automatically.
+
+    :param str label: The name of the parameter from which ``obj`` was taken
+        (so a developer can easily find the source of the problem and correct
+        it).
+
+    :return: If ``obj`` is the text string type, a ``bytes`` object giving the
+        UTF-8 encoding of that text is returned.  Otherwise, ``obj`` itself is
+        returned.
+    """
+    if isinstance(obj, text_type):
+        warn(
+            _TEXT_WARNING.format(label),
+            category=DeprecationWarning,
+            stacklevel=3
+        )
+        return obj.encode('utf-8')
+    return obj
diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py
index 678c048..9061a4a 100644
--- a/OpenSSL/crypto.py
+++ b/OpenSSL/crypto.py
@@ -2,6 +2,7 @@
 from base64 import b16encode
 from functools import partial
 from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
+from warnings import warn as _warn
 
 from six import (
     integer_types as _integer_types,
@@ -13,7 +14,10 @@
     lib as _lib,
     exception_from_error_queue as _exception_from_error_queue,
     byte_string as _byte_string,
-    native as _native)
+    native as _native,
+    UNSPECIFIED as _UNSPECIFIED,
+    text_to_bytes_and_warn as _text_to_bytes_and_warn,
+)
 
 FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
 FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
@@ -25,6 +29,7 @@
 TYPE_DSA = _lib.EVP_PKEY_DSA
 
 
+
 class Error(Exception):
     """
     An error occurred in an `OpenSSL.crypto` API.
@@ -33,6 +38,8 @@
 
 _raise_current_error = partial(_exception_from_error_queue, Error)
 
+
+
 def _untested_error(where):
     """
     An OpenSSL API failed somehow.  Additionally, the failure which was
@@ -1493,6 +1500,125 @@
 X509StoreType = X509Store
 
 
+class X509StoreContextError(Exception):
+    """
+    An error occurred while verifying a certificate using
+    `OpenSSL.X509StoreContext.verify_certificate`.
+
+    :ivar certificate: The certificate which caused verificate failure.
+    :type cert: :class:`X509`
+
+    """
+    def __init__(self, message, certificate):
+        super(X509StoreContextError, self).__init__(message)
+        self.certificate = certificate
+
+
+class X509StoreContext(object):
+    """
+    An X.509 store context.
+
+    An :py:class:`X509StoreContext` is used to define some of the criteria for
+    certificate verification.  The information encapsulated in this object
+    includes, but is not limited to, a set of trusted certificates,
+    verification parameters, and revoked certificates.
+
+    Of these, only the set of trusted certificates is currently exposed.
+
+    :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
+        instance.  It is dynamically allocated and automatically garbage
+        collected.
+
+    :ivar _store: See the ``store`` ``__init__`` parameter.
+
+    :ivar _cert: See the ``certificate`` ``__init__`` parameter.
+    """
+
+    def __init__(self, store, certificate):
+        """
+        :param X509Store store: The certificates which will be trusted for the
+            purposes of any verifications.
+
+        :param X509 certificate: The certificate to be verified.
+        """
+        store_ctx = _lib.X509_STORE_CTX_new()
+        self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
+        self._store = store
+        self._cert = certificate
+        # Make the store context available for use after instantiating this
+        # class by initializing it now. Per testing, subsequent calls to
+        # :py:meth:`_init` have no adverse affect.
+        self._init()
+
+
+    def _init(self):
+        """
+        Set up the store context for a subsequent verification operation.
+        """
+        ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
+        if ret <= 0:
+            _raise_current_error()
+
+
+    def _cleanup(self):
+        """
+        Internally cleans up the store context.
+
+        The store context can then be reused with a new call to
+        :py:meth:`_init`.
+        """
+        _lib.X509_STORE_CTX_cleanup(self._store_ctx)
+
+
+    def _exception_from_context(self):
+        """
+        Convert an OpenSSL native context error failure into a Python
+        exception.
+
+        When a call to native OpenSSL X509_verify_cert fails, additonal information
+        about the failure can be obtained from the store context.
+        """
+        errors = [
+            _lib.X509_STORE_CTX_get_error(self._store_ctx),
+            _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
+            _native(_ffi.string(_lib.X509_verify_cert_error_string(
+                        _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
+        ]
+        # A context error should always be associated with a certificate, so we
+        # expect this call to never return :class:`None`.
+        _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
+        _cert = _lib.X509_dup(_x509)
+        pycert = X509.__new__(X509)
+        pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
+        return X509StoreContextError(errors, pycert)
+
+
+    def set_store(self, store):
+        """
+        Set the context's trust store.
+
+        :param X509Store store: The certificates which will be trusted for the
+            purposes of any *future* verifications.
+        """
+        self._store = store
+
+
+    def verify_certificate(self):
+        """
+        Verify a certificate in a context.
+
+        :param store_ctx: The :py:class:`X509StoreContext` to verify.
+        :raises: Error
+        """
+        # Always re-initialize the store context in case
+        # :py:meth:`verify_certificate` is called multiple times.
+        self._init()
+        ret = _lib.X509_verify_cert(self._store_ctx)
+        self._cleanup()
+        if ret <= 0:
+            raise self._exception_from_context()
+
+
 
 def load_certificate(type, buffer):
     """
@@ -1875,7 +2001,8 @@
             _raise_current_error()
 
 
-    def export(self, cert, key, type=FILETYPE_PEM, days=100):
+    def export(self, cert, key, type=FILETYPE_PEM, days=100,
+               digest=_UNSPECIFIED):
         """
         Export a CRL as a string.
 
@@ -1888,10 +2015,12 @@
         :param type: The export format, either :py:data:`FILETYPE_PEM`,
             :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
 
-        :param days: The number of days until the next update of this CRL.
-        :type days: :py:data:`int`
+        :param int days: The number of days until the next update of this CRL.
 
-        :return: :py:data:`str`
+        :param bytes digest: The name of the message digest to use (eg
+            ``b"sha1"``).
+
+        :return: :py:data:`bytes`
         """
         if not isinstance(cert, X509):
             raise TypeError("cert must be an X509 instance")
@@ -1900,6 +2029,19 @@
         if not isinstance(type, int):
             raise TypeError("type must be an integer")
 
+        if digest is _UNSPECIFIED:
+            _warn(
+                "The default message digest (md5) is deprecated.  "
+                "Pass the name of a message digest explicitly.",
+                category=DeprecationWarning,
+                stacklevel=2,
+            )
+            digest = b"md5"
+
+        digest_obj = _lib.EVP_get_digestbyname(digest)
+        if digest_obj == _ffi.NULL:
+            raise ValueError("No such digest method")
+
         bio = _lib.BIO_new(_lib.BIO_s_mem())
         if bio == _ffi.NULL:
             # TODO: This is untested.
@@ -1919,7 +2061,7 @@
 
         _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
 
-        sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, _lib.EVP_md5())
+        sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
         if not sign_result:
             _raise_current_error()
 
@@ -2074,7 +2216,7 @@
 
     def set_ca_certificates(self, cacerts):
         """
-        Set the CA certificates in the PKCS #12 structure.
+        Replace or set the CA certificates within the PKCS12 object.
 
         :param cacerts: The new CA certificates, or :py:const:`None` to unset
             them.
@@ -2138,6 +2280,8 @@
         :return: The string representation of the PKCS #12 structure.
         :rtype:
         """
+        passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
+
         if self._cacerts is None:
             cacerts = _ffi.NULL
         else:
@@ -2454,6 +2598,8 @@
     :param digest: message digest to use
     :return: signature
     """
+    data = _text_to_bytes_and_warn("data", data)
+
     digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
     if digest_obj == _ffi.NULL:
         raise ValueError("No such digest method")
@@ -2488,6 +2634,8 @@
     :param digest: message digest to use
     :return: :py:const:`None` if the signature is correct, raise exception otherwise
     """
+    data = _text_to_bytes_and_warn("data", data)
+
     digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
     if digest_obj == _ffi.NULL:
         raise ValueError("No such digest method")
@@ -2509,7 +2657,6 @@
         _raise_current_error()
 
 
-
 def load_crl(type, buffer):
     """
     Load a certificate revocation list from a buffer
@@ -2556,7 +2703,7 @@
     if type == FILETYPE_PEM:
         pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
     elif type == FILETYPE_ASN1:
-        pass
+        pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
     else:
         # TODO: This is untested.
         _raise_current_error()
@@ -2579,6 +2726,8 @@
     :param passphrase: (Optional) The password to decrypt the PKCS12 lump
     :returns: The PKCS12 object
     """
+    passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
+
     if isinstance(buffer, _text_type):
         buffer = buffer.encode("ascii")
 
@@ -2692,3 +2841,9 @@
 # This is similar but exercised mainly by exception_from_error_queue.  It calls
 # both ERR_load_crypto_strings() and ERR_load_SSL_strings().
 _lib.SSL_load_error_strings()
+
+
+
+# Set the default string mask to match OpenSSL upstream (since 2005) and
+# RFC5280 recommendations.
+_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')
diff --git a/OpenSSL/rand.py b/OpenSSL/rand.py
index e754378..3adf693 100644
--- a/OpenSSL/rand.py
+++ b/OpenSSL/rand.py
@@ -11,7 +11,8 @@
 from OpenSSL._util import (
     ffi as _ffi,
     lib as _lib,
-    exception_from_error_queue as _exception_from_error_queue)
+    exception_from_error_queue as _exception_from_error_queue,
+    path_string as _path_string)
 
 
 class Error(Exception):
@@ -131,13 +132,13 @@
     """
     Seed the PRNG with data from a file
 
-    :param filename: The file to read data from
-    :param maxbytes: (optional) The number of bytes to read, default is
-                     to read the entire file
+    :param filename: The file to read data from (``bytes`` or ``unicode``).
+    :param maxbytes: (optional) The number of bytes to read, default is to read
+        the entire file
+
     :return: The number of bytes read
     """
-    if not isinstance(filename, _builtin_bytes):
-        raise TypeError("filename must be a string")
+    filename = _path_string(filename)
 
     if maxbytes is _unspecified:
         maxbytes = -1
@@ -152,12 +153,11 @@
     """
     Save PRNG state to a file
 
-    :param filename: The file to write data to
+    :param filename: The file to write data to (``bytes`` or ``unicode``).
+
     :return: The number of bytes written
     """
-    if not isinstance(filename, _builtin_bytes):
-        raise TypeError("filename must be a string")
-
+    filename = _path_string(filename)
     return _lib.RAND_write_file(filename)
 
 
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index bbe5d05..b817451 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -6,16 +6,22 @@
 """
 
 from unittest import main
+from warnings import catch_warnings, simplefilter
 
-import os, re
+import base64
+import os
+import re
 from subprocess import PIPE, Popen
 from datetime import datetime, timedelta
 
-from six import u, b, binary_type
+from six import u, b, binary_type, PY3
+from warnings import simplefilter
+from warnings import catch_warnings
 
 from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
 from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
-from OpenSSL.crypto import X509Store, X509StoreType, X509Req, X509ReqType
+from OpenSSL.crypto import X509Store, X509StoreType, X509StoreContext, X509StoreContextError
+from OpenSSL.crypto import X509Req, X509ReqType
 from OpenSSL.crypto import X509Extension, X509ExtensionType
 from OpenSSL.crypto import load_certificate, load_privatekey
 from OpenSSL.crypto import FILETYPE_PEM, FILETYPE_ASN1, FILETYPE_TEXT
@@ -27,7 +33,9 @@
 from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType
 from OpenSSL.crypto import (
     sign, verify, get_elliptic_curve, get_elliptic_curves)
-from OpenSSL.test.util import EqualityTestsMixin, TestCase
+from OpenSSL.test.util import (
+    EqualityTestsMixin, TestCase, WARNING_TYPE_EXPECTED
+)
 from OpenSSL._util import native, lib
 
 def normalize_certificate_pem(pem):
@@ -81,6 +89,40 @@
 -----END RSA PRIVATE KEY-----
 """)
 
+intermediate_cert_pem = b("""-----BEGIN CERTIFICATE-----
+MIICVzCCAcCgAwIBAgIRAMPzhm6//0Y/g2pmnHR2C4cwDQYJKoZIhvcNAQENBQAw
+WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAw
+DgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwHhcNMTQw
+ODI4MDIwNDA4WhcNMjQwODI1MDIwNDA4WjBmMRUwEwYDVQQDEwxpbnRlcm1lZGlh
+dGUxDDAKBgNVBAoTA29yZzERMA8GA1UECxMIb3JnLXVuaXQxCzAJBgNVBAYTAlVT
+MQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU2FuIERpZWdvMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmK
+FGIbljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT
+21H2qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwID
+AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAPIWSkLX
+QRMApOjjyC+tMxumT5e2pMqChHmxobQK4NMdrf2VCx+cRT6EmY8sK3/Xl/X8UBQ+
+9n5zXb1ZwhW/sTWgUvmOceJ4/XVs9FkdWOOn1J0XBch9ZIiFe/s5ASIgG7fUdcUF
+9mAWS6FK2ca3xIh5kIupCXOFa0dPvlw/YUFT
+-----END CERTIFICATE-----
+""")
+
+intermediate_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmKFGIb
+ljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT21H2
+qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwIDAQAB
+AoGAfSZVV80pSeOKHTYfbGdNY/jHdU9eFUa/33YWriXU+77EhpIItJjkRRgivIfo
+rhFJpBSGmDLblaqepm8emsXMeH4+2QzOYIf0QGGP6E6scjTt1PLqdqKfVJ1a2REN
+147cujNcmFJb/5VQHHMpaPTgttEjlzuww4+BCDPsVRABWrkCQQD3loH36nLoQTtf
++kQq0T6Bs9/UWkTAGo0ND81ALj0F8Ie1oeZg6RNT96RxZ3aVuFTESTv6/TbjWywO
+wdzlmV1vAkEA38rTJ6PTwaJlw5OttdDzAXGPB9tDmzh9oSi7cHwQQXizYd8MBYx4
+sjHUKD3dCQnb1dxJFhd3BT5HsnkRMbVZXQJAbXduH17ZTzcIOXc9jHDXYiFVZV5D
+52vV0WCbLzVCZc3jMrtSUKa8lPN5EWrdU3UchWybyG0MR5mX8S5lrF4SoQJAIyUD
+DBKaSqpqONCUUx1BTFS9FYrFjzbL4+c1qHCTTPTblt8kUCrDOZjBrKAqeiTmNSum
+/qUot9YUBF8m6BuGsQJATHHmdFy/fG1VLkyBp49CAa8tN3Z5r/CgTznI4DfMTf4C
+NbRHn2UmYlwQBa+L5lg9phewNe8aEwpPyPLoV85U8Q==
+-----END RSA PRIVATE KEY-----
+""")
+
 server_cert_pem = b("""-----BEGIN CERTIFICATE-----
 MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
 BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
@@ -114,6 +156,40 @@
 -----END RSA PRIVATE KEY-----
 """))
 
+intermediate_server_cert_pem = b("""-----BEGIN CERTIFICATE-----
+MIICWDCCAcGgAwIBAgIRAPQFY9jfskSihdiNSNdt6GswDQYJKoZIhvcNAQENBQAw
+ZjEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
+CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
+biBEaWVnbzAeFw0xNDA4MjgwMjEwNDhaFw0yNDA4MjUwMjEwNDhaMG4xHTAbBgNV
+BAMTFGludGVybWVkaWF0ZS1zZXJ2aWNlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
+CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
+biBEaWVnbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqpJZygd+w1faLOr1
+iOAmbBhx5SZWcTCZ/ZjHQTJM7GuPT624QkqsixFghRKdDROwpwnAP7gMRukLqiy4
++kRuGT5OfyGggL95i2xqA+zehjj08lSTlvGHpePJgCyTavIy5+Ljsj4DKnKyuhxm
+biXTRrH83NDgixVkObTEmh/OVK0CAwEAATANBgkqhkiG9w0BAQ0FAAOBgQBa0Npw
+UkzjaYEo1OUE1sTI6Mm4riTIHMak4/nswKh9hYup//WVOlr/RBSBtZ7Q/BwbjobN
+3bfAtV7eSAqBsfxYXyof7G1ALANQERkq3+oyLP1iVt08W1WOUlIMPhdCF/QuCwy6
+x9MJLhUCGLJPM+O2rAPWVD9wCmvq10ALsiH3yA==
+-----END CERTIFICATE-----
+""")
+
+intermediate_server_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCqklnKB37DV9os6vWI4CZsGHHlJlZxMJn9mMdBMkzsa49PrbhC
+SqyLEWCFEp0NE7CnCcA/uAxG6QuqLLj6RG4ZPk5/IaCAv3mLbGoD7N6GOPTyVJOW
+8Yel48mALJNq8jLn4uOyPgMqcrK6HGZuJdNGsfzc0OCLFWQ5tMSaH85UrQIDAQAB
+AoGAIQ594j5zna3/9WaPsTgnmhlesVctt4AAx/n827DA4ayyuHFlXUuVhtoWR5Pk
+5ezj9mtYW8DyeCegABnsu2vZni/CdvU6uiS1Hv6qM1GyYDm9KWgovIP9rQCDSGaz
+d57IWVGxx7ODFkm3gN5nxnSBOFVHytuW1J7FBRnEsehRroECQQDXHFOv82JuXDcz
+z3+4c74IEURdOHcbycxlppmK9kFqm5lsUdydnnGW+mvwDk0APOB7Wg7vyFyr393e
+dpmBDCzNAkEAyv6tVbTKUYhSjW+QhabJo896/EqQEYUmtMXxk4cQnKeR/Ao84Rkf
+EqD5IykMUfUI0jJU4DGX+gWZ10a7kNbHYQJAVFCuHNFxS4Cpwo0aqtnzKoZaHY/8
+X9ABZfafSHCtw3Op92M+7ikkrOELXdS9KdKyyqbKJAKNEHF3LbOfB44WIQJAA2N4
+9UNNVUsXRbElEnYUS529CdUczo4QdVgQjkvk5RiPAUwSdBd9Q0xYnFOlFwEmIowg
+ipWJWe0aAlP18ZcEQQJBAL+5lekZ/GUdQoZ4HAsN5a9syrzavJ9VvU1KOOPorPZK
+nMRZbbQgP+aSB7yl6K0gaLaZ8XaK0pjxNBh6ASqg9f4=
+-----END RSA PRIVATE KEY-----
+""")
+
 client_cert_pem = b("""-----BEGIN CERTIFICATE-----
 MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
 BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
@@ -248,6 +324,27 @@
 -----END PKCS7-----
 """)
 
+pkcs7DataASN1 = base64.b64decode(b"""
+MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExADALBgkqhkiG9w0BBwGgggMKMIID
+BjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzERMA8G
+A1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQDExtN
+MkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNA
+cG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzELMAkG
+A1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhvc3Qx
+HTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEBBQAD
+SwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh5kwI
+zOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAw
+LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G
+A1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7hyNp
+65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y
+Q3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8g
+Q2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNv
+bYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6BoJu
+VwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++7QGG
+/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JEWUQ9
+Ho4EzbYCOaEAMQA=
+""")
+
 crlData = b("""\
 -----BEGIN X509 CRL-----
 MIIBWzCBxTANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
@@ -513,7 +610,7 @@
 
     def test_issuer(self):
         """
-        If an extension requires a issuer, the :py:data:`issuer` parameter to
+        If an extension requires an issuer, the :py:data:`issuer` parameter to
         :py:class:`X509Extension` provides its value.
         """
         ext2 = X509Extension(
@@ -906,7 +1003,7 @@
         self.assertEqual(
             a.der(),
             b('0\x1b1\x0b0\t\x06\x03U\x04\x06\x13\x02US'
-              '1\x0c0\n\x06\x03U\x04\x03\x13\x03foo'))
+              '1\x0c0\n\x06\x03U\x04\x03\x0c\x03foo'))
 
 
     def test_get_components(self):
@@ -1189,7 +1286,7 @@
     def test_verify_success(self):
         """
         :py:obj:`X509Req.verify` returns :py:obj:`True` if called with a
-        :py:obj:`OpenSSL.crypto.PKey` which represents the public part ofthe key
+        :py:obj:`OpenSSL.crypto.PKey` which represents the public part of the key
         which signed the request.
         """
         request = X509Req()
@@ -1465,19 +1562,29 @@
         cert.gmtime_adj_notAfter(2)
         self.assertFalse(cert.has_expired())
 
+    def test_root_has_not_expired(self):
+        """
+        :py:obj:`X509Type.has_expired` returns :py:obj:`False` if the certificate's not-after
+        time is in the future.
+        """
+        cert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        self.assertFalse(cert.has_expired())
+
 
     def test_digest(self):
         """
         :py:obj:`X509.digest` returns a string giving ":"-separated hex-encoded words
         of the digest of the certificate.
         """
-        cert = X509()
+        cert = load_certificate(FILETYPE_PEM, root_cert_pem)
         self.assertEqual(
             # This is MD5 instead of GOOD_DIGEST because the digest algorithm
             # actually matters to the assertion (ie, another arbitrary, good
             # digest will not product the same digest).
+            # Digest verified with the command:
+            # openssl x509 -in root_cert.pem -noout -fingerprint -md5
             cert.digest("MD5"),
-            b("A8:EB:07:F8:53:25:0A:F2:56:05:C5:A5:C4:C4:C7:15"))
+            b("19:B3:05:26:2B:F8:F2:FF:0B:8F:21:07:A8:28:B8:75"))
 
 
     def _extcert(self, pkey, extensions):
@@ -1490,6 +1597,7 @@
         cert.set_notAfter(when)
 
         cert.add_extensions(extensions)
+        cert.sign(pkey, 'sha1')
         return load_certificate(
             FILETYPE_PEM, dump_certificate(FILETYPE_PEM, cert))
 
@@ -1969,6 +2077,31 @@
         self.verify_pkcs12_container(p12)
 
 
+    def test_load_pkcs12_text_passphrase(self):
+        """
+        A PKCS12 string generated using the openssl command line can be loaded
+        with :py:obj:`load_pkcs12` and its components extracted and examined.
+        Using text as passphrase instead of bytes. DeprecationWarning expected.
+        """
+        pem = client_key_pem + client_cert_pem
+        passwd = b"whatever"
+        p12_str = _runopenssl(pem, b"pkcs12", b"-export", b"-clcerts",
+                              b"-passout", b"pass:" + passwd)
+        with catch_warnings(record=True) as w:
+            simplefilter("always")
+            p12 = load_pkcs12(p12_str, passphrase=b"whatever".decode("ascii"))
+
+            self.assertEqual(
+                "{0} for passphrase is no longer accepted, use bytes".format(
+                    WARNING_TYPE_EXPECTED
+                ),
+                str(w[-1].message)
+            )
+            self.assertIs(w[-1].category, DeprecationWarning)
+
+        self.verify_pkcs12_container(p12)
+
+
     def test_load_pkcs12_no_passphrase(self):
         """
         A PKCS12 string generated using openssl command line can be loaded with
@@ -2170,6 +2303,26 @@
             dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b"")
 
 
+    def test_export_without_bytes(self):
+        """
+        Test :py:obj:`PKCS12.export` with text not bytes as passphrase
+        """
+        p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
+
+        with catch_warnings(record=True) as w:
+            simplefilter("always")
+            dumped_p12 = p12.export(passphrase=b"randomtext".decode("ascii"))
+            self.assertEqual(
+                "{0} for passphrase is no longer accepted, use bytes".format(
+                    WARNING_TYPE_EXPECTED
+                ),
+                str(w[-1].message)
+            )
+            self.assertIs(w[-1].category, DeprecationWarning)
+        self.check_recovery(
+            dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b"randomtext")
+
+
     def test_key_cert_mismatch(self):
         """
         :py:obj:`PKCS12.export` raises an exception when a key and certificate
@@ -2560,7 +2713,7 @@
             dump_privatekey, FILETYPE_PEM, key, GOOD_CIPHER, cb)
 
 
-    def test_load_pkcs7_data(self):
+    def test_load_pkcs7_data_pem(self):
         """
         :py:obj:`load_pkcs7_data` accepts a PKCS#7 string and returns an instance of
         :py:obj:`PKCS7Type`.
@@ -2569,6 +2722,15 @@
         self.assertTrue(isinstance(pkcs7, PKCS7Type))
 
 
+    def test_load_pkcs7_data_asn1(self):
+        """
+        :py:obj:`load_pkcs7_data` accepts a bytes containing ASN1 data
+        representing PKCS#7 and returns an instance of :py:obj`PKCS7Type`.
+        """
+        pkcs7 = load_pkcs7_data(FILETYPE_ASN1, pkcs7DataASN1)
+        self.assertTrue(isinstance(pkcs7, PKCS7Type))
+
+
     def test_load_pkcs7_data_invalid(self):
         """
         If the data passed to :py:obj:`load_pkcs7_data` is invalid,
@@ -2893,11 +3055,9 @@
         self.assertRaises(TypeError, CRL, None)
 
 
-    def test_export(self):
+    def _get_crl(self):
         """
-        Use python to create a simple CRL with a revocation, and export
-        the CRL in formats of PEM, DER and text.  Those outputs are verified
-        with the openssl program.
+        Get a new ``CRL`` with a revocation.
         """
         crl = CRL()
         revoked = Revoked()
@@ -2906,26 +3066,110 @@
         revoked.set_serial(b('3ab'))
         revoked.set_reason(b('sUpErSeDEd'))
         crl.add_revoked(revoked)
+        return crl
 
+
+    def test_export_pem(self):
+        """
+        If not passed a format, ``CRL.export`` returns a "PEM" format string
+        representing a serial number, a revoked reason, and certificate issuer
+        information.
+        """
+        crl = self._get_crl()
         # PEM format
         dumped_crl = crl.export(self.cert, self.pkey, days=20)
         text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
+
+        # These magic values are based on the way the CRL above was constructed
+        # and with what certificate it was exported.
         text.index(b('Serial Number: 03AB'))
         text.index(b('Superseded'))
-        text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA'))
+        text.index(
+            b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')
+        )
+
+
+    def test_export_der(self):
+        """
+        If passed ``FILETYPE_ASN1`` for the format, ``CRL.export`` returns a
+        "DER" format string representing a serial number, a revoked reason, and
+        certificate issuer information.
+        """
+        crl = self._get_crl()
 
         # DER format
         dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1)
-        text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER")
+        text = _runopenssl(
+            dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER"
+        )
         text.index(b('Serial Number: 03AB'))
         text.index(b('Superseded'))
-        text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA'))
+        text.index(
+            b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')
+        )
+
+
+    def test_export_text(self):
+        """
+        If passed ``FILETYPE_TEXT`` for the format, ``CRL.export`` returns a
+        text format string like the one produced by the openssl command line
+        tool.
+        """
+        crl = self._get_crl()
+
+        dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1)
+        text = _runopenssl(
+            dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER"
+        )
 
         # text format
         dumped_text = crl.export(self.cert, self.pkey, type=FILETYPE_TEXT)
         self.assertEqual(text, dumped_text)
 
 
+    def test_export_custom_digest(self):
+        """
+        If passed the name of a digest function, ``CRL.export`` uses a
+        signature algorithm based on that digest function.
+        """
+        crl = self._get_crl()
+        dumped_crl = crl.export(self.cert, self.pkey, digest=b"sha1")
+        text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
+        text.index(b('Signature Algorithm: sha1'))
+
+
+    def test_export_md5_digest(self):
+        """
+        If passed md5 as the digest function, ``CRL.export`` uses md5 and does
+        not emit a deprecation warning.
+        """
+        crl = self._get_crl()
+        with catch_warnings(record=True) as catcher:
+            simplefilter("always")
+            self.assertEqual(0, len(catcher))
+        dumped_crl = crl.export(self.cert, self.pkey, digest=b"md5")
+        text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
+        text.index(b('Signature Algorithm: md5'))
+
+
+    def test_export_default_digest(self):
+        """
+        If not passed the name of a digest function, ``CRL.export`` uses a
+        signature algorithm based on MD5 and emits a deprecation warning.
+        """
+        crl = self._get_crl()
+        with catch_warnings(record=True) as catcher:
+            simplefilter("always")
+            dumped_crl = crl.export(self.cert, self.pkey)
+            self.assertEqual(
+                "The default message digest (md5) is deprecated.  "
+                "Pass the name of a message digest explicitly.",
+                str(catcher[0].message),
+            )
+        text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
+        text.index(b('Signature Algorithm: md5'))
+
+
     def test_export_invalid(self):
         """
         If :py:obj:`CRL.export` is used with an uninitialized :py:obj:`X509`
@@ -2956,7 +3200,7 @@
         crl = CRL()
         self.assertRaises(TypeError, crl.export)
         self.assertRaises(TypeError, crl.export, self.cert)
-        self.assertRaises(TypeError, crl.export, self.cert, self.pkey, FILETYPE_PEM, 10, "foo")
+        self.assertRaises(TypeError, crl.export, self.cert, self.pkey, FILETYPE_PEM, 10, "md5", "foo")
 
         self.assertRaises(TypeError, crl.export, None, self.pkey, FILETYPE_PEM, 10)
         self.assertRaises(TypeError, crl.export, self.cert, None, FILETYPE_PEM, 10)
@@ -2974,6 +3218,19 @@
         self.assertRaises(ValueError, crl.export, self.cert, self.pkey, 100, 10)
 
 
+    def test_export_unknown_digest(self):
+        """
+        Calling :py:obj:`OpenSSL.CRL.export` with a unsupported digest results
+        in a :py:obj:`ValueError` being raised.
+        """
+        crl = CRL()
+        self.assertRaises(
+            ValueError,
+            crl.export,
+            self.cert, self.pkey, FILETYPE_PEM, 10, b"strange-digest"
+        )
+
+
     def test_get_revoked(self):
         """
         Use python to create a simple CRL with two revocations.
@@ -3074,6 +3331,107 @@
 
 
 
+class X509StoreContextTests(TestCase):
+    """
+    Tests for :py:obj:`OpenSSL.crypto.X509StoreContext`.
+    """
+    root_cert = load_certificate(FILETYPE_PEM, root_cert_pem)
+    intermediate_cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem)
+    intermediate_server_cert = load_certificate(FILETYPE_PEM, intermediate_server_cert_pem)
+
+    def test_valid(self):
+        """
+        :py:obj:`verify_certificate` returns ``None`` when called with a certificate
+        and valid chain.
+        """
+        store = X509Store()
+        store.add_cert(self.root_cert)
+        store.add_cert(self.intermediate_cert)
+        store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+        self.assertEqual(store_ctx.verify_certificate(), None)
+
+
+    def test_reuse(self):
+        """
+        :py:obj:`verify_certificate` can be called multiple times with the same
+        ``X509StoreContext`` instance to produce the same result.
+        """
+        store = X509Store()
+        store.add_cert(self.root_cert)
+        store.add_cert(self.intermediate_cert)
+        store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+        self.assertEqual(store_ctx.verify_certificate(), None)
+        self.assertEqual(store_ctx.verify_certificate(), None)
+
+
+    def test_trusted_self_signed(self):
+        """
+        :py:obj:`verify_certificate` returns ``None`` when called with a self-signed
+        certificate and itself in the chain.
+        """
+        store = X509Store()
+        store.add_cert(self.root_cert)
+        store_ctx = X509StoreContext(store, self.root_cert)
+        self.assertEqual(store_ctx.verify_certificate(), None)
+
+
+    def test_untrusted_self_signed(self):
+        """
+        :py:obj:`verify_certificate` raises error when a self-signed certificate is
+        verified without itself in the chain.
+        """
+        store = X509Store()
+        store_ctx = X509StoreContext(store, self.root_cert)
+        e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
+        self.assertEqual(e.args[0][2], 'self signed certificate')
+        self.assertEqual(e.certificate.get_subject().CN, 'Testing Root CA')
+
+
+    def test_invalid_chain_no_root(self):
+        """
+        :py:obj:`verify_certificate` raises error when a root certificate is missing
+        from the chain.
+        """
+        store = X509Store()
+        store.add_cert(self.intermediate_cert)
+        store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+        e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
+        self.assertEqual(e.args[0][2], 'unable to get issuer certificate')
+        self.assertEqual(e.certificate.get_subject().CN, 'intermediate')
+
+
+    def test_invalid_chain_no_intermediate(self):
+        """
+        :py:obj:`verify_certificate` raises error when an intermediate certificate is
+        missing from the chain.
+        """
+        store = X509Store()
+        store.add_cert(self.root_cert)
+        store_ctx = X509StoreContext(store, self.intermediate_server_cert)
+        e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
+        self.assertEqual(e.args[0][2], 'unable to get local issuer certificate')
+        self.assertEqual(e.certificate.get_subject().CN, 'intermediate-service')
+
+
+    def test_modification_pre_verify(self):
+        """
+        :py:obj:`verify_certificate` can use a store context modified after
+        instantiation.
+        """
+        store_bad = X509Store()
+        store_bad.add_cert(self.intermediate_cert)
+        store_good = X509Store()
+        store_good.add_cert(self.root_cert)
+        store_good.add_cert(self.intermediate_cert)
+        store_ctx = X509StoreContext(store_bad, self.intermediate_server_cert)
+        e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
+        self.assertEqual(e.args[0][2], 'unable to get issuer certificate')
+        self.assertEqual(e.certificate.get_subject().CN, 'intermediate')
+        store_ctx.set_store(store_good)
+        self.assertEqual(store_ctx.verify_certificate(), None)
+
+
+
 class SignVerifyTests(TestCase):
     """
     Tests for :py:obj:`OpenSSL.crypto.sign` and :py:obj:`OpenSSL.crypto.verify`.
@@ -3119,6 +3477,47 @@
             ValueError, verify, good_cert, sig, content, "strange-digest")
 
 
+    def test_sign_verify_with_text(self):
+        """
+        :py:obj:`sign` generates a cryptographic signature which :py:obj:`verify` can check.
+        Deprecation warnings raised because using text instead of bytes as content
+        """
+        content = (
+            b"It was a bright cold day in April, and the clocks were striking "
+            b"thirteen. Winston Smith, his chin nuzzled into his breast in an "
+            b"effort to escape the vile wind, slipped quickly through the "
+            b"glass doors of Victory Mansions, though not quickly enough to "
+            b"prevent a swirl of gritty dust from entering along with him."
+        ).decode("ascii")
+
+        priv_key = load_privatekey(FILETYPE_PEM, root_key_pem)
+        cert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        for digest in ['md5', 'sha1']:
+            with catch_warnings(record=True) as w:
+                simplefilter("always")
+                sig = sign(priv_key, content, digest)
+
+                self.assertEqual(
+                    "{0} for data is no longer accepted, use bytes".format(
+                        WARNING_TYPE_EXPECTED
+                    ),
+                    str(w[-1].message)
+                )
+                self.assertIs(w[-1].category, DeprecationWarning)
+
+            with catch_warnings(record=True) as w:
+                simplefilter("always")
+                verify(cert, sig, content, digest)
+
+                self.assertEqual(
+                    "{0} for data is no longer accepted, use bytes".format(
+                        WARNING_TYPE_EXPECTED
+                    ),
+                    str(w[-1].message)
+                )
+                self.assertIs(w[-1].category, DeprecationWarning)
+
+
     def test_sign_nulls(self):
         """
         :py:obj:`sign` produces a signature for a string with embedded nulls.
diff --git a/OpenSSL/test/test_rand.py b/OpenSSL/test/test_rand.py
index c52cb6b..3d5c290 100644
--- a/OpenSSL/test/test_rand.py
+++ b/OpenSSL/test/test_rand.py
@@ -10,7 +10,7 @@
 import stat
 import sys
 
-from OpenSSL.test.util import TestCase, b
+from OpenSSL.test.util import NON_ASCII, TestCase, b
 from OpenSSL import rand
 
 
@@ -176,27 +176,47 @@
         self.assertRaises(TypeError, rand.write_file, None)
         self.assertRaises(TypeError, rand.write_file, "foo", None)
 
+    def _read_write_test(self, path):
+        """
+        Verify that ``rand.write_file`` and ``rand.load_file`` can be used.
+        """
+        # Create the file so cleanup is more straightforward
+        with open(path, "w"):
+            pass
 
-    def test_files(self):
-        """
-        Test reading and writing of files via rand functions.
-        """
-        # Write random bytes to a file
-        tmpfile = self.mktemp()
-        # Make sure it exists (so cleanup definitely succeeds)
-        fObj = open(tmpfile, 'w')
-        fObj.close()
         try:
-            rand.write_file(tmpfile)
+            # Write random bytes to a file
+            rand.write_file(path)
+
             # Verify length of written file
-            size = os.stat(tmpfile)[stat.ST_SIZE]
+            size = os.stat(path)[stat.ST_SIZE]
             self.assertEqual(1024, size)
+
             # Read random bytes from file
-            rand.load_file(tmpfile)
-            rand.load_file(tmpfile, 4)  # specify a length
+            rand.load_file(path)
+            rand.load_file(path, 4)  # specify a length
         finally:
             # Cleanup
-            os.unlink(tmpfile)
+            os.unlink(path)
+
+
+    def test_bytes_paths(self):
+        """
+        Random data can be saved and loaded to files with paths specified as
+        bytes.
+        """
+        path = self.mktemp()
+        path += NON_ASCII.encode(sys.getfilesystemencoding())
+        self._read_write_test(path)
+
+
+    def test_unicode_paths(self):
+        """
+        Random data can be saved and loaded to files with paths specified as
+        unicode.
+        """
+        path = self.mktemp().decode('utf-8') + NON_ASCII
+        self._read_write_test(path)
 
 
 if __name__ == '__main__':
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py
index 6409b8e..1f231c9 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/OpenSSL/test/test_ssl.py
@@ -7,12 +7,13 @@
 
 from gc import collect, get_referrers
 from errno import ECONNREFUSED, EINPROGRESS, EWOULDBLOCK, EPIPE, ESHUTDOWN
-from sys import platform, version_info
+from sys import platform, getfilesystemencoding
 from socket import SHUT_RDWR, error, socket
 from os import makedirs
 from os.path import join
 from unittest import main
 from weakref import ref
+from warnings import catch_warnings, simplefilter
 
 from six import PY3, text_type, u
 
@@ -22,7 +23,6 @@
 from OpenSSL.crypto import dump_certificate, load_certificate
 from OpenSSL.crypto import get_elliptic_curves
 
-from OpenSSL.SSL import _lib
 from OpenSSL.SSL import OPENSSL_VERSION_NUMBER, SSLEAY_VERSION, SSLEAY_CFLAGS
 from OpenSSL.SSL import SSLEAY_PLATFORM, SSLEAY_DIR, SSLEAY_BUILT_ON
 from OpenSSL.SSL import SENT_SHUTDOWN, RECEIVED_SHUTDOWN
@@ -43,10 +43,11 @@
 from OpenSSL.SSL import (
     Context, ContextType, Session, Connection, ConnectionType, SSLeay_version)
 
-from OpenSSL.test.util import TestCase, b
+from OpenSSL._util import lib as _lib
+
+from OpenSSL.test.util import WARNING_TYPE_EXPECTED, NON_ASCII, TestCase, b
 from OpenSSL.test.test_crypto import (
-    cleartextCertificatePEM, cleartextPrivateKeyPEM)
-from OpenSSL.test.test_crypto import (
+    cleartextCertificatePEM, cleartextPrivateKeyPEM,
     client_cert_pem, client_key_pem, server_cert_pem, server_key_pem,
     root_cert_pem)
 
@@ -95,6 +96,23 @@
 """
 
 
+def join_bytes_or_unicode(prefix, suffix):
+    """
+    Join two path components of either ``bytes`` or ``unicode``.
+
+    The return type is the same as the type of ``prefix``.
+    """
+    # If the types are the same, nothing special is necessary.
+    if type(prefix) == type(suffix):
+        return join(prefix, suffix)
+
+    # Otherwise, coerce suffix to the type of prefix.
+    if isinstance(prefix, text_type):
+        return join(prefix, suffix.decode(getfilesystemencoding()))
+    else:
+        return join(prefix, suffix.encode(getfilesystemencoding()))
+
+
 def verify_cb(conn, cert, errnum, depth, ok):
     return ok
 
@@ -395,23 +413,52 @@
         self.assertRaises(Error, ctx.use_privatekey_file, self.mktemp())
 
 
+    def _use_privatekey_file_test(self, pemfile, filetype):
+        """
+        Verify that calling ``Context.use_privatekey_file`` with the given
+        arguments does not raise an exception.
+        """
+        key = PKey()
+        key.generate_key(TYPE_RSA, 128)
+
+        with open(pemfile, "wt") as pem:
+            pem.write(
+                dump_privatekey(FILETYPE_PEM, key).decode("ascii")
+            )
+
+        ctx = Context(TLSv1_METHOD)
+        ctx.use_privatekey_file(pemfile, filetype)
+
+
+    def test_use_privatekey_file_bytes(self):
+        """
+        A private key can be specified from a file by passing a ``bytes``
+        instance giving the file name to ``Context.use_privatekey_file``.
+        """
+        self._use_privatekey_file_test(
+            self.mktemp() + NON_ASCII.encode(getfilesystemencoding()),
+            FILETYPE_PEM,
+        )
+
+
+    def test_use_privatekey_file_unicode(self):
+        """
+        A private key can be specified from a file by passing a ``unicode``
+        instance giving the file name to ``Context.use_privatekey_file``.
+        """
+        self._use_privatekey_file_test(
+            self.mktemp().decode(getfilesystemencoding()) + NON_ASCII,
+            FILETYPE_PEM,
+        )
+
+
     if not PY3:
         def test_use_privatekey_file_long(self):
             """
             On Python 2 :py:obj:`Context.use_privatekey_file` accepts a
             filetype of type :py:obj:`long` as well as :py:obj:`int`.
             """
-            pemfile = self.mktemp()
-
-            key = PKey()
-            key.generate_key(TYPE_RSA, 128)
-
-            with open(pemfile, "wt") as pem:
-                pem.write(
-                    dump_privatekey(FILETYPE_PEM, key).decode("ascii"))
-
-            ctx = Context(TLSv1_METHOD)
-            ctx.use_privatekey_file(pemfile, long(FILETYPE_PEM))
+            self._use_privatekey_file_test(self.mktemp(), long(FILETYPE_PEM))
 
 
     def test_use_certificate_wrong_args(self):
@@ -476,21 +523,40 @@
         self.assertRaises(Error, ctx.use_certificate_file, self.mktemp())
 
 
-    def test_use_certificate_file(self):
+    def _use_certificate_file_test(self, certificate_file):
         """
-        :py:obj:`Context.use_certificate` sets the certificate which will be
-        used to identify connections created using the context.
+        Verify that calling ``Context.use_certificate_file`` with the given
+        filename doesn't raise an exception.
         """
         # TODO
         # Hard to assert anything.  But we could set a privatekey then ask
         # OpenSSL if the cert and key agree using check_privatekey.  Then as
         # long as check_privatekey works right we're good...
-        pem_filename = self.mktemp()
-        with open(pem_filename, "wb") as pem_file:
+        with open(certificate_file, "wb") as pem_file:
             pem_file.write(cleartextCertificatePEM)
 
         ctx = Context(TLSv1_METHOD)
-        ctx.use_certificate_file(pem_filename)
+        ctx.use_certificate_file(certificate_file)
+
+
+    def test_use_certificate_file_bytes(self):
+        """
+        :py:obj:`Context.use_certificate_file` sets the certificate (given as a
+        ``bytes`` filename) which will be used to identify connections created
+        using the context.
+        """
+        filename = self.mktemp() + NON_ASCII.encode(getfilesystemencoding())
+        self._use_certificate_file_test(filename)
+
+
+    def test_use_certificate_file_unicode(self):
+        """
+        :py:obj:`Context.use_certificate_file` sets the certificate (given as a
+        ``bytes`` filename) which will be used to identify connections created
+        using the context.
+        """
+        filename = self.mktemp().decode(getfilesystemencoding()) + NON_ASCII
+        self._use_certificate_file_test(filename)
 
 
     if not PY3:
@@ -507,6 +573,43 @@
             ctx.use_certificate_file(pem_filename, long(FILETYPE_PEM))
 
 
+    def test_check_privatekey_valid(self):
+        """
+        :py:obj:`Context.check_privatekey` returns :py:obj:`None` if the
+        :py:obj:`Context` instance has been configured to use a matched key and
+        certificate pair.
+        """
+        key = load_privatekey(FILETYPE_PEM, client_key_pem)
+        cert = load_certificate(FILETYPE_PEM, client_cert_pem)
+        context = Context(TLSv1_METHOD)
+        context.use_privatekey(key)
+        context.use_certificate(cert)
+        self.assertIs(None, context.check_privatekey())
+
+
+    def test_check_privatekey_invalid(self):
+        """
+        :py:obj:`Context.check_privatekey` raises :py:obj:`Error` if the
+        :py:obj:`Context` instance has been configured to use a key and
+        certificate pair which don't relate to each other.
+        """
+        key = load_privatekey(FILETYPE_PEM, client_key_pem)
+        cert = load_certificate(FILETYPE_PEM, server_cert_pem)
+        context = Context(TLSv1_METHOD)
+        context.use_privatekey(key)
+        context.use_certificate(cert)
+        self.assertRaises(Error, context.check_privatekey)
+
+
+    def test_check_privatekey_wrong_args(self):
+        """
+        :py:obj:`Context.check_privatekey` raises :py:obj:`TypeError` if called
+        with other than no arguments.
+        """
+        context = Context(TLSv1_METHOD)
+        self.assertRaises(TypeError, context.check_privatekey, object())
+
+
     def test_set_app_data_wrong_args(self):
         """
         :py:obj:`Context.set_app_data` raises :py:obj:`TypeError` if called with other than
@@ -867,12 +970,13 @@
         self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
 
 
-    def test_load_verify_file(self):
+    def _load_verify_cafile(self, cafile):
         """
-        :py:obj:`Context.load_verify_locations` accepts a file name and uses the
-        certificates within for verification purposes.
+        Verify that if path to a file containing a certificate is passed to
+        ``Context.load_verify_locations`` for the ``cafile`` parameter, that
+        certificate is used as a trust root for the purposes of verifying
+        connections created using that ``Context``.
         """
-        cafile = self.mktemp()
         fObj = open(cafile, 'w')
         fObj.write(cleartextCertificatePEM.decode('ascii'))
         fObj.close()
@@ -880,6 +984,27 @@
         self._load_verify_locations_test(cafile)
 
 
+    def test_load_verify_bytes_cafile(self):
+        """
+        :py:obj:`Context.load_verify_locations` accepts a file name as a
+        ``bytes`` instance and uses the certificates within for verification
+        purposes.
+        """
+        cafile = self.mktemp() + NON_ASCII.encode(getfilesystemencoding())
+        self._load_verify_cafile(cafile)
+
+
+    def test_load_verify_unicode_cafile(self):
+        """
+        :py:obj:`Context.load_verify_locations` accepts a file name as a
+        ``unicode`` instance and uses the certificates within for verification
+        purposes.
+        """
+        self._load_verify_cafile(
+            self.mktemp().decode(getfilesystemencoding()) + NON_ASCII
+        )
+
+
     def test_load_verify_invalid_file(self):
         """
         :py:obj:`Context.load_verify_locations` raises :py:obj:`Error` when passed a
@@ -890,25 +1015,47 @@
             Error, clientContext.load_verify_locations, self.mktemp())
 
 
-    def test_load_verify_directory(self):
+    def _load_verify_directory_locations_capath(self, capath):
         """
-        :py:obj:`Context.load_verify_locations` accepts a directory name and uses
-        the certificates within for verification purposes.
+        Verify that if path to a directory containing certificate files is
+        passed to ``Context.load_verify_locations`` for the ``capath``
+        parameter, those certificates are used as trust roots for the purposes
+        of verifying connections created using that ``Context``.
         """
-        capath = self.mktemp()
         makedirs(capath)
         # Hash values computed manually with c_rehash to avoid depending on
         # c_rehash in the test suite.  One is from OpenSSL 0.9.8, the other
         # from OpenSSL 1.0.0.
         for name in [b'c7adac82.0', b'c3705638.0']:
-            cafile = join(capath, name)
-            fObj = open(cafile, 'w')
-            fObj.write(cleartextCertificatePEM.decode('ascii'))
-            fObj.close()
+            cafile = join_bytes_or_unicode(capath, name)
+            with open(cafile, 'w') as fObj:
+                fObj.write(cleartextCertificatePEM.decode('ascii'))
 
         self._load_verify_locations_test(None, capath)
 
 
+    def test_load_verify_directory_bytes_capath(self):
+        """
+        :py:obj:`Context.load_verify_locations` accepts a directory name as a
+        ``bytes`` instance and uses the certificates within for verification
+        purposes.
+        """
+        self._load_verify_directory_locations_capath(
+            self.mktemp() + NON_ASCII.encode(getfilesystemencoding())
+        )
+
+
+    def test_load_verify_directory_unicode_capath(self):
+        """
+        :py:obj:`Context.load_verify_locations` accepts a directory name as a
+        ``unicode`` instance and uses the certificates within for verification
+        purposes.
+        """
+        self._load_verify_directory_locations_capath(
+            self.mktemp().decode(getfilesystemencoding()) + NON_ASCII
+        )
+
+
     def test_load_verify_locations_wrong_args(self):
         """
         :py:obj:`Context.load_verify_locations` raises :py:obj:`TypeError` if called with
@@ -938,8 +1085,8 @@
             # in a unit test is bad, but it's the only way I can think of to
             # really test this. -exarkun
 
-            # Arg, verisign.com doesn't speak TLSv1
-            context = Context(SSLv3_METHOD)
+            # Arg, verisign.com doesn't speak anything newer than TLS 1.0
+            context = Context(TLSv1_METHOD)
             context.set_default_verify_paths()
             context.set_verify(
                 VERIFY_PEER,
@@ -1052,11 +1199,11 @@
 
     def test_add_extra_chain_cert(self):
         """
-        :py:obj:`Context.add_extra_chain_cert` accepts an :py:obj:`X509` instance to add to
-        the certificate chain.
+        :py:obj:`Context.add_extra_chain_cert` accepts an :py:obj:`X509`
+        instance to add to the certificate chain.
 
-        See :py:obj:`_create_certificate_chain` for the details of the certificate
-        chain tested.
+        See :py:obj:`_create_certificate_chain` for the details of the
+        certificate chain tested.
 
         The chain is tested by starting a server with scert and connecting
         to it with a client which trusts cacert and requires verification to
@@ -1067,15 +1214,17 @@
 
         # Dump the CA certificate to a file because that's the only way to load
         # it as a trusted CA in the client context.
-        for cert, name in [(cacert, 'ca.pem'), (icert, 'i.pem'), (scert, 's.pem')]:
-            fObj = open(name, 'w')
-            fObj.write(dump_certificate(FILETYPE_PEM, cert).decode('ascii'))
-            fObj.close()
+        for cert, name in [(cacert, 'ca.pem'),
+                           (icert, 'i.pem'),
+                           (scert, 's.pem')]:
+            with open(join(self.tmpdir, name), 'w') as f:
+                f.write(dump_certificate(FILETYPE_PEM, cert).decode('ascii'))
 
-        for key, name in [(cakey, 'ca.key'), (ikey, 'i.key'), (skey, 's.key')]:
-            fObj = open(name, 'w')
-            fObj.write(dump_privatekey(FILETYPE_PEM, key).decode('ascii'))
-            fObj.close()
+        for key, name in [(cakey, 'ca.key'),
+                          (ikey, 'i.key'),
+                          (skey, 's.key')]:
+            with open(join(self.tmpdir, name), 'w') as f:
+                f.write(dump_privatekey(FILETYPE_PEM, key).decode('ascii'))
 
         # Create the server context
         serverContext = Context(TLSv1_METHOD)
@@ -1088,49 +1237,73 @@
         clientContext = Context(TLSv1_METHOD)
         clientContext.set_verify(
             VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb)
-        clientContext.load_verify_locations(b"ca.pem")
+        clientContext.load_verify_locations(join(self.tmpdir, "ca.pem"))
 
         # Try it out.
         self._handshake_test(serverContext, clientContext)
 
 
-    def test_use_certificate_chain_file(self):
+    def _use_certificate_chain_file_test(self, certdir):
         """
-        :py:obj:`Context.use_certificate_chain_file` reads a certificate chain from
-        the specified file.
+        Verify that :py:obj:`Context.use_certificate_chain_file` reads a
+        certificate chain from a specified file.
 
-        The chain is tested by starting a server with scert and connecting
-        to it with a client which trusts cacert and requires verification to
+        The chain is tested by starting a server with scert and connecting to
+        it with a client which trusts cacert and requires verification to
         succeed.
         """
         chain = _create_certificate_chain()
         [(cakey, cacert), (ikey, icert), (skey, scert)] = chain
 
+        makedirs(certdir)
+
+        chainFile = join_bytes_or_unicode(certdir, "chain.pem")
+        caFile = join_bytes_or_unicode(certdir, "ca.pem")
+
         # Write out the chain file.
-        chainFile = self.mktemp()
-        fObj = open(chainFile, 'wb')
-        # Most specific to least general.
-        fObj.write(dump_certificate(FILETYPE_PEM, scert))
-        fObj.write(dump_certificate(FILETYPE_PEM, icert))
-        fObj.write(dump_certificate(FILETYPE_PEM, cacert))
-        fObj.close()
+        with open(chainFile, 'wb') as fObj:
+            # Most specific to least general.
+            fObj.write(dump_certificate(FILETYPE_PEM, scert))
+            fObj.write(dump_certificate(FILETYPE_PEM, icert))
+            fObj.write(dump_certificate(FILETYPE_PEM, cacert))
+
+        with open(caFile, 'w') as fObj:
+            fObj.write(dump_certificate(FILETYPE_PEM, cacert).decode('ascii'))
 
         serverContext = Context(TLSv1_METHOD)
         serverContext.use_certificate_chain_file(chainFile)
         serverContext.use_privatekey(skey)
 
-        fObj = open('ca.pem', 'w')
-        fObj.write(dump_certificate(FILETYPE_PEM, cacert).decode('ascii'))
-        fObj.close()
-
         clientContext = Context(TLSv1_METHOD)
         clientContext.set_verify(
             VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb)
-        clientContext.load_verify_locations(b"ca.pem")
+        clientContext.load_verify_locations(caFile)
 
         self._handshake_test(serverContext, clientContext)
 
 
+    def test_use_certificate_chain_file_bytes(self):
+        """
+        ``Context.use_certificate_chain_file`` accepts the name of a file (as
+        an instance of ``bytes``) to specify additional certificates to use to
+        construct and verify a trust chain.
+        """
+        self._use_certificate_chain_file_test(
+            self.mktemp() + NON_ASCII.encode(getfilesystemencoding())
+        )
+
+
+    def test_use_certificate_chain_file_unicode(self):
+        """
+        ``Context.use_certificate_chain_file`` accepts the name of a file (as
+        an instance of ``unicode``) to specify additional certificates to use
+        to construct and verify a trust chain.
+        """
+        self._use_certificate_chain_file_test(
+            self.mktemp().decode(getfilesystemencoding()) + NON_ASCII
+        )
+
+
     def test_use_certificate_chain_file_wrong_args(self):
         """
         :py:obj:`Context.use_certificate_chain_file` raises :py:obj:`TypeError`
@@ -1205,20 +1378,39 @@
         self.assertRaises(Error, context.load_tmp_dh, b"hello")
 
 
-    def test_load_tmp_dh(self):
+    def _load_tmp_dh_test(self, dhfilename):
         """
-        :py:obj:`Context.load_tmp_dh` loads Diffie-Hellman parameters from the
-        specified file.
+        Verify that calling ``Context.load_tmp_dh`` with the given filename
+        does not raise an exception.
         """
         context = Context(TLSv1_METHOD)
-        dhfilename = self.mktemp()
-        dhfile = open(dhfilename, "w")
-        dhfile.write(dhparam)
-        dhfile.close()
+        with open(dhfilename, "w") as dhfile:
+            dhfile.write(dhparam)
+
         context.load_tmp_dh(dhfilename)
         # XXX What should I assert here? -exarkun
 
 
+    def test_load_tmp_dh_bytes(self):
+        """
+        :py:obj:`Context.load_tmp_dh` loads Diffie-Hellman parameters from the
+        specified file (given as ``bytes``).
+        """
+        self._load_tmp_dh_test(
+            self.mktemp() + NON_ASCII.encode(getfilesystemencoding()),
+        )
+
+
+    def test_load_tmp_dh_unicode(self):
+        """
+        :py:obj:`Context.load_tmp_dh` loads Diffie-Hellman parameters from the
+        specified file (given as ``unicode``).
+        """
+        self._load_tmp_dh_test(
+            self.mktemp().decode(getfilesystemencoding()) + NON_ASCII,
+        )
+
+
     def test_set_tmp_ecdh(self):
         """
         :py:obj:`Context.set_tmp_ecdh` sets the elliptic curve for
@@ -1434,6 +1626,396 @@
         self.assertEqual([(server, b("foo1.example.com"))], args)
 
 
+class NextProtoNegotiationTests(TestCase, _LoopbackMixin):
+    """
+    Test for Next Protocol Negotiation in PyOpenSSL.
+    """
+    if _lib.Cryptography_HAS_NEXTPROTONEG:
+        def test_npn_success(self):
+            """
+            Tests that clients and servers that agree on the negotiated next
+            protocol can correct establish a connection, and that the agreed
+            protocol is reported by the connections.
+            """
+            advertise_args = []
+            select_args = []
+            def advertise(conn):
+                advertise_args.append((conn,))
+                return [b'http/1.1', b'spdy/2']
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b'spdy/2'
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_npn_advertise_callback(advertise)
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_npn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            self._interactInMemory(server, client)
+
+            self.assertEqual([(server,)], advertise_args)
+            self.assertEqual([(client, [b'http/1.1', b'spdy/2'])], select_args)
+
+            self.assertEqual(server.get_next_proto_negotiated(), b'spdy/2')
+            self.assertEqual(client.get_next_proto_negotiated(), b'spdy/2')
+
+
+        def test_npn_client_fail(self):
+            """
+            Tests that when clients and servers cannot agree on what protocol
+            to use next that the TLS connection does not get established.
+            """
+            advertise_args = []
+            select_args = []
+            def advertise(conn):
+                advertise_args.append((conn,))
+                return [b'http/1.1', b'spdy/2']
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b''
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_npn_advertise_callback(advertise)
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_npn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            # If the client doesn't return anything, the connection will fail.
+            self.assertRaises(Error, self._interactInMemory, server, client)
+
+            self.assertEqual([(server,)], advertise_args)
+            self.assertEqual([(client, [b'http/1.1', b'spdy/2'])], select_args)
+
+
+        def test_npn_select_error(self):
+            """
+            Test that we can handle exceptions in the select callback. If
+            select fails it should be fatal to the connection.
+            """
+            advertise_args = []
+            def advertise(conn):
+                advertise_args.append((conn,))
+                return [b'http/1.1', b'spdy/2']
+            def select(conn, options):
+                raise TypeError
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_npn_advertise_callback(advertise)
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_npn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            # If the callback throws an exception it should be raised here.
+            self.assertRaises(
+                TypeError, self._interactInMemory, server, client
+            )
+            self.assertEqual([(server,)], advertise_args)
+
+
+        def test_npn_advertise_error(self):
+            """
+            Test that we can handle exceptions in the advertise callback. If
+            advertise fails no NPN is advertised to the client.
+            """
+            select_args = []
+            def advertise(conn):
+                raise TypeError
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b''
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_npn_advertise_callback(advertise)
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_npn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            # If the client doesn't return anything, the connection will fail.
+            self.assertRaises(
+                TypeError, self._interactInMemory, server, client
+            )
+            self.assertEqual([], select_args)
+
+    else:
+        # No NPN.
+        def test_npn_not_implemented(self):
+            # Test the context methods first.
+            context = Context(TLSv1_METHOD)
+            fail_methods = [
+                context.set_npn_advertise_callback,
+                context.set_npn_select_callback,
+            ]
+            for method in fail_methods:
+                self.assertRaises(
+                    NotImplementedError, method, None
+                )
+
+            # Now test a connection.
+            conn = Connection(context)
+            fail_methods = [
+                conn.get_next_proto_negotiated,
+            ]
+            for method in fail_methods:
+                self.assertRaises(NotImplementedError, method)
+
+
+
+class ApplicationLayerProtoNegotiationTests(TestCase, _LoopbackMixin):
+    """
+    Tests for ALPN in PyOpenSSL.
+    """
+    # Skip tests on versions that don't support ALPN.
+    if _lib.Cryptography_HAS_ALPN:
+
+        def test_alpn_success(self):
+            """
+            Clients and servers that agree on the negotiated ALPN protocol can
+            correct establish a connection, and the agreed protocol is reported
+            by the connections.
+            """
+            select_args = []
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b'spdy/2'
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_alpn_protos([b'http/1.1', b'spdy/2'])
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_alpn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            self._interactInMemory(server, client)
+
+            self.assertEqual([(server, [b'http/1.1', b'spdy/2'])], select_args)
+
+            self.assertEqual(server.get_alpn_proto_negotiated(), b'spdy/2')
+            self.assertEqual(client.get_alpn_proto_negotiated(), b'spdy/2')
+
+
+        def test_alpn_set_on_connection(self):
+            """
+            The same as test_alpn_success, but setting the ALPN protocols on
+            the connection rather than the context.
+            """
+            select_args = []
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b'spdy/2'
+
+            # Setup the client context but don't set any ALPN protocols.
+            client_context = Context(TLSv1_METHOD)
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_alpn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            # Set the ALPN protocols on the client connection.
+            client = Connection(client_context, None)
+            client.set_alpn_protos([b'http/1.1', b'spdy/2'])
+            client.set_connect_state()
+
+            self._interactInMemory(server, client)
+
+            self.assertEqual([(server, [b'http/1.1', b'spdy/2'])], select_args)
+
+            self.assertEqual(server.get_alpn_proto_negotiated(), b'spdy/2')
+            self.assertEqual(client.get_alpn_proto_negotiated(), b'spdy/2')
+
+
+        def test_alpn_server_fail(self):
+            """
+            When clients and servers cannot agree on what protocol to use next
+            the TLS connection does not get established.
+            """
+            select_args = []
+            def select(conn, options):
+                select_args.append((conn, options))
+                return b''
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_alpn_protos([b'http/1.1', b'spdy/2'])
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_alpn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            # If the client doesn't return anything, the connection will fail.
+            self.assertRaises(Error, self._interactInMemory, server, client)
+
+            self.assertEqual([(server, [b'http/1.1', b'spdy/2'])], select_args)
+
+
+        def test_alpn_no_server(self):
+            """
+            When clients and servers cannot agree on what protocol to use next
+            because the server doesn't offer ALPN, no protocol is negotiated.
+            """
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_alpn_protos([b'http/1.1', b'spdy/2'])
+
+            server_context = Context(TLSv1_METHOD)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            # Do the dance.
+            self._interactInMemory(server, client)
+
+            self.assertEqual(client.get_alpn_proto_negotiated(), b'')
+
+
+        def test_alpn_callback_exception(self):
+            """
+            We can handle exceptions in the ALPN select callback.
+            """
+            select_args = []
+            def select(conn, options):
+                select_args.append((conn, options))
+                raise TypeError()
+
+            client_context = Context(TLSv1_METHOD)
+            client_context.set_alpn_protos([b'http/1.1', b'spdy/2'])
+
+            server_context = Context(TLSv1_METHOD)
+            server_context.set_alpn_select_callback(select)
+
+            # Necessary to actually accept the connection
+            server_context.use_privatekey(
+                load_privatekey(FILETYPE_PEM, server_key_pem))
+            server_context.use_certificate(
+                load_certificate(FILETYPE_PEM, server_cert_pem))
+
+            # Do a little connection to trigger the logic
+            server = Connection(server_context, None)
+            server.set_accept_state()
+
+            client = Connection(client_context, None)
+            client.set_connect_state()
+
+            self.assertRaises(
+                TypeError, self._interactInMemory, server, client
+            )
+            self.assertEqual([(server, [b'http/1.1', b'spdy/2'])], select_args)
+
+    else:
+        # No ALPN.
+        def test_alpn_not_implemented(self):
+            """
+            If ALPN is not in OpenSSL, we should raise NotImplementedError.
+            """
+            # Test the context methods first.
+            context = Context(TLSv1_METHOD)
+            self.assertRaises(
+                NotImplementedError, context.set_alpn_protos, None
+            )
+            self.assertRaises(
+                NotImplementedError, context.set_alpn_select_callback, None
+            )
+
+            # Now test a connection.
+            conn = Connection(context)
+            self.assertRaises(
+                NotImplementedError, context.set_alpn_protos, None
+            )
+
+
 
 class SessionTests(TestCase):
     """
@@ -1555,7 +2137,7 @@
         self.assertRaises(
             TypeError, conn.set_tlsext_host_name, b("with\0null"))
 
-        if version_info >= (3,):
+        if PY3:
             # On Python 3.x, don't accidentally implicitly convert from text.
             self.assertRaises(
                 TypeError,
@@ -1709,6 +2291,40 @@
         self.assertEquals(server.get_shutdown(), SENT_SHUTDOWN|RECEIVED_SHUTDOWN)
 
 
+    def test_shutdown_closed(self):
+        """
+        If the underlying socket is closed, :py:obj:`Connection.shutdown` propagates the
+        write error from the low level write call.
+        """
+        server, client = self._loopback()
+        server.sock_shutdown(2)
+        exc = self.assertRaises(SysCallError, server.shutdown)
+        if platform == "win32":
+            self.assertEqual(exc.args[0], ESHUTDOWN)
+        else:
+            self.assertEqual(exc.args[0], EPIPE)
+
+
+    def test_shutdown_truncated(self):
+        """
+        If the underlying connection is truncated, :obj:`Connection.shutdown`
+        raises an :obj:`Error`.
+        """
+        server_ctx = Context(TLSv1_METHOD)
+        client_ctx = Context(TLSv1_METHOD)
+        server_ctx.use_privatekey(
+            load_privatekey(FILETYPE_PEM, server_key_pem))
+        server_ctx.use_certificate(
+            load_certificate(FILETYPE_PEM, server_cert_pem))
+        server = Connection(server_ctx, None)
+        client = Connection(client_ctx, None)
+        self._handshakeInMemory(client, server)
+        self.assertEqual(server.shutdown(), False)
+        self.assertRaises(WantReadError, server.shutdown)
+        server.bio_shutdown()
+        self.assertRaises(Error, server.shutdown)
+
+
     def test_set_shutdown(self):
         """
         :py:obj:`Connection.set_shutdown` sets the state of the SSL connection shutdown
@@ -2182,6 +2798,26 @@
         self.assertEquals(count, 2)
         self.assertEquals(client.recv(2), b('xy'))
 
+
+    def test_text(self):
+        """
+        When passed a text, :py:obj:`Connection.send` transmits all of it and
+        returns the number of bytes sent. It also raises a DeprecationWarning.
+        """
+        server, client = self._loopback()
+        with catch_warnings(record=True) as w:
+            simplefilter("always")
+            count = server.send(b"xy".decode("ascii"))
+            self.assertEqual(
+                "{0} for buf is no longer accepted, use bytes".format(
+                    WARNING_TYPE_EXPECTED
+                ),
+                str(w[-1].message)
+            )
+            self.assertIs(w[-1].category, DeprecationWarning)
+        self.assertEquals(count, 2)
+        self.assertEquals(client.recv(2), b"xy")
+
     try:
         memoryview
     except NameError:
@@ -2217,6 +2853,164 @@
 
 
 
+def _make_memoryview(size):
+    """
+    Create a new ``memoryview`` wrapped around a ``bytearray`` of the given
+    size.
+    """
+    return memoryview(bytearray(size))
+
+
+
+class ConnectionRecvIntoTests(TestCase, _LoopbackMixin):
+    """
+    Tests for :py:obj:`Connection.recv_into`
+    """
+    def _no_length_test(self, factory):
+        """
+        Assert that when the given buffer is passed to
+        ``Connection.recv_into``, whatever bytes are available to be received
+        that fit into that buffer are written into that buffer.
+        """
+        output_buffer = factory(5)
+
+        server, client = self._loopback()
+        server.send(b('xy'))
+
+        self.assertEqual(client.recv_into(output_buffer), 2)
+        self.assertEqual(output_buffer, bytearray(b('xy\x00\x00\x00')))
+
+
+    def test_bytearray_no_length(self):
+        """
+        :py:obj:`Connection.recv_into` can be passed a ``bytearray`` instance
+        and data in the receive buffer is written to it.
+        """
+        self._no_length_test(bytearray)
+
+
+    def _respects_length_test(self, factory):
+        """
+        Assert that when the given buffer is passed to ``Connection.recv_into``
+        along with a value for ``nbytes`` that is less than the size of that
+        buffer, only ``nbytes`` bytes are written into the buffer.
+        """
+        output_buffer = factory(10)
+
+        server, client = self._loopback()
+        server.send(b('abcdefghij'))
+
+        self.assertEqual(client.recv_into(output_buffer, 5), 5)
+        self.assertEqual(
+            output_buffer, bytearray(b('abcde\x00\x00\x00\x00\x00'))
+        )
+
+
+    def test_bytearray_respects_length(self):
+        """
+        When called with a ``bytearray`` instance,
+        :py:obj:`Connection.recv_into` respects the ``nbytes`` parameter and
+        doesn't copy in more than that number of bytes.
+        """
+        self._respects_length_test(bytearray)
+
+
+    def _doesnt_overfill_test(self, factory):
+        """
+        Assert that if there are more bytes available to be read from the
+        receive buffer than would fit into the buffer passed to
+        :py:obj:`Connection.recv_into`, only as many as fit are written into
+        it.
+        """
+        output_buffer = factory(5)
+
+        server, client = self._loopback()
+        server.send(b('abcdefghij'))
+
+        self.assertEqual(client.recv_into(output_buffer), 5)
+        self.assertEqual(output_buffer, bytearray(b('abcde')))
+        rest = client.recv(5)
+        self.assertEqual(b('fghij'), rest)
+
+
+    def test_bytearray_doesnt_overfill(self):
+        """
+        When called with a ``bytearray`` instance,
+        :py:obj:`Connection.recv_into` respects the size of the array and
+        doesn't write more bytes into it than will fit.
+        """
+        self._doesnt_overfill_test(bytearray)
+
+
+    def _really_doesnt_overfill_test(self, factory):
+        """
+        Assert that if the value given by ``nbytes`` is greater than the actual
+        size of the output buffer passed to :py:obj:`Connection.recv_into`, the
+        behavior is as if no value was given for ``nbytes`` at all.
+        """
+        output_buffer = factory(5)
+
+        server, client = self._loopback()
+        server.send(b('abcdefghij'))
+
+        self.assertEqual(client.recv_into(output_buffer, 50), 5)
+        self.assertEqual(output_buffer, bytearray(b('abcde')))
+        rest = client.recv(5)
+        self.assertEqual(b('fghij'), rest)
+
+
+    def test_bytearray_really_doesnt_overfill(self):
+        """
+        When called with a ``bytearray`` instance and an ``nbytes`` value that
+        is too large, :py:obj:`Connection.recv_into` respects the size of the
+        array and not the ``nbytes`` value and doesn't write more bytes into
+        the buffer than will fit.
+        """
+        self._doesnt_overfill_test(bytearray)
+
+
+    try:
+        memoryview
+    except NameError:
+        "cannot test recv_into memoryview without memoryview"
+    else:
+        def test_memoryview_no_length(self):
+            """
+            :py:obj:`Connection.recv_into` can be passed a ``memoryview``
+            instance and data in the receive buffer is written to it.
+            """
+            self._no_length_test(_make_memoryview)
+
+
+        def test_memoryview_respects_length(self):
+            """
+            When called with a ``memoryview`` instance,
+            :py:obj:`Connection.recv_into` respects the ``nbytes`` parameter
+            and doesn't copy more than that number of bytes in.
+            """
+            self._respects_length_test(_make_memoryview)
+
+
+        def test_memoryview_doesnt_overfill(self):
+            """
+            When called with a ``memoryview`` instance,
+            :py:obj:`Connection.recv_into` respects the size of the array and
+            doesn't write more bytes into it than will fit.
+            """
+            self._doesnt_overfill_test(_make_memoryview)
+
+
+        def test_memoryview_really_doesnt_overfill(self):
+            """
+            When called with a ``memoryview`` instance and an ``nbytes`` value
+            that is too large, :py:obj:`Connection.recv_into` respects the size
+            of the array and not the ``nbytes`` value and doesn't write more
+            bytes into the buffer than will fit.
+            """
+            self._doesnt_overfill_test(_make_memoryview)
+
+
+
 class ConnectionSendallTests(TestCase, _LoopbackMixin):
     """
     Tests for :py:obj:`Connection.sendall`.
@@ -2244,6 +3038,25 @@
         self.assertEquals(client.recv(1), b('x'))
 
 
+    def test_text(self):
+        """
+        :py:obj:`Connection.sendall` transmits all the content in the string
+        passed to it raising a DeprecationWarning in case of this being a text.
+        """
+        server, client = self._loopback()
+        with catch_warnings(record=True) as w:
+            simplefilter("always")
+            server.sendall(b"x".decode("ascii"))
+            self.assertEqual(
+                "{0} for buf is no longer accepted, use bytes".format(
+                    WARNING_TYPE_EXPECTED
+                ),
+                str(w[-1].message)
+            )
+            self.assertIs(w[-1].category, DeprecationWarning)
+        self.assertEquals(client.recv(1), b"x")
+
+
     try:
         memoryview
     except NameError:
diff --git a/OpenSSL/test/test_util.py b/OpenSSL/test/test_util.py
new file mode 100644
index 0000000..8d92a3c
--- /dev/null
+++ b/OpenSSL/test/test_util.py
@@ -0,0 +1,17 @@
+from OpenSSL._util import exception_from_error_queue, lib
+from OpenSSL.test.util import TestCase
+
+
+
+class ErrorTests(TestCase):
+    """
+    Tests for handling of certain OpenSSL error cases.
+    """
+    def test_exception_from_error_queue_nonexistent_reason(self):
+        """
+        :py:func:`exception_from_error_queue` raises ``ValueError`` when it
+        encounters an OpenSSL error code which does not have a reason string.
+        """
+        lib.ERR_put_error(lib.ERR_LIB_EVP, 0, 1112, b"", 10)
+        exc = self.assertRaises(ValueError, exception_from_error_queue, ValueError)
+        self.assertEqual(exc.args[0][0][2], "")
diff --git a/OpenSSL/test/util.py b/OpenSSL/test/util.py
index 21bbdc4..78b4a3f 100644
--- a/OpenSSL/test/util.py
+++ b/OpenSSL/test/util.py
@@ -7,16 +7,20 @@
 U{Twisted<http://twistedmatrix.com/>}.
 """
 
+import os
 import shutil
-import traceback
-import os, os.path
-from tempfile import mktemp
-from unittest import TestCase
 import sys
+import traceback
+
+from tempfile import mktemp, mkdtemp
+from unittest import TestCase
+
+from six import PY3
 
 from OpenSSL._util import exception_from_error_queue
 from OpenSSL.crypto import Error
 
+
 try:
     import memdbg
 except Exception:
@@ -25,10 +29,17 @@
 
 from OpenSSL._util import ffi, lib, byte_string as b
 
+
+
+# This is the UTF-8 encoding of the SNOWMAN unicode code point.
+NON_ASCII = b("\xe2\x98\x83").decode("utf-8")
+
+
+
 class TestCase(TestCase):
     """
-    :py:class:`TestCase` adds useful testing functionality beyond what is available
-    from the standard library :py:class:`unittest.TestCase`.
+    :py:class:`TestCase` adds useful testing functionality beyond what is
+    available from the standard library :py:class:`unittest.TestCase`.
     """
     def run(self, result):
         run = super(TestCase, self).run
@@ -150,24 +161,38 @@
                     (None, Exception(stack % (allocs_report,)), None))
 
 
+    _tmpdir = None
+
+
+    @property
+    def tmpdir(self):
+        """
+        On demand create a temporary directory.
+        """
+        if self._tmpdir is not None:
+            return self._tmpdir
+
+        self._tmpdir = mkdtemp(dir=".")
+        return self._tmpdir
+
+
     def tearDown(self):
         """
-        Clean up any files or directories created using :py:meth:`TestCase.mktemp`.
-        Subclasses must invoke this method if they override it or the
-        cleanup will not occur.
+        Clean up any files or directories created using
+        :py:meth:`TestCase.mktemp`.  Subclasses must invoke this method if they
+        override it or the cleanup will not occur.
         """
-        if False and self._temporaryFiles is not None:
-            for temp in self._temporaryFiles:
-                if os.path.isdir(temp):
-                    shutil.rmtree(temp)
-                elif os.path.exists(temp):
-                    os.unlink(temp)
+        if self._tmpdir is not None:
+            shutil.rmtree(self._tmpdir)
+
         try:
             exception_from_error_queue(Error)
         except Error:
             e = sys.exc_info()[1]
             if e.args != ([],):
-                self.fail("Left over errors in OpenSSL error queue: " + repr(e))
+                self.fail(
+                    "Left over errors in OpenSSL error queue: " + repr(e)
+                )
 
 
     def assertIsInstance(self, instance, classOrTuple, message=None):
@@ -227,7 +252,7 @@
     failIfIn = assertNotIn
 
 
-    def failUnlessIdentical(self, first, second, msg=None):
+    def assertIs(self, first, second, msg=None):
         """
         Fail the test if :py:data:`first` is not :py:data:`second`.  This is an
         obect-identity-equality test, not an object equality
@@ -239,10 +264,10 @@
         if first is not second:
             raise self.failureException(msg or '%r is not %r' % (first, second))
         return first
-    assertIdentical = failUnlessIdentical
+    assertIdentical = failUnlessIdentical = assertIs
 
 
-    def failIfIdentical(self, first, second, msg=None):
+    def assertIsNot(self, first, second, msg=None):
         """
         Fail the test if :py:data:`first` is :py:data:`second`.  This is an
         obect-identity-equality test, not an object equality
@@ -254,7 +279,7 @@
         if first is second:
             raise self.failureException(msg or '%r is %r' % (first, second))
         return first
-    assertNotIdentical = failIfIdentical
+    assertNotIdentical = failIfIdentical = assertIsNot
 
 
     def failUnlessRaises(self, exception, f, *args, **kwargs):
@@ -288,16 +313,13 @@
     assertRaises = failUnlessRaises
 
 
-    _temporaryFiles = None
     def mktemp(self):
         """
-        Pathetic substitute for twisted.trial.unittest.TestCase.mktemp.
+        Return UTF-8-encoded bytes of a path to a tmp file.
+
+        The file will be cleaned up after the test run.
         """
-        if self._temporaryFiles is None:
-            self._temporaryFiles = []
-        temp = b(mktemp(dir="."))
-        self._temporaryFiles.append(temp)
-        return temp
+        return mktemp(dir=self.tmpdir).encode("utf-8")
 
 
     # Other stuff
@@ -447,3 +469,10 @@
         a = self.anInstance()
         b = Delegate()
         self.assertEqual(a != b, [b])
+
+
+# The type name expected in warnings about using the wrong string type.
+if PY3:
+    WARNING_TYPE_EXPECTED = "str"
+else:
+    WARNING_TYPE_EXPECTED = "unicode"
diff --git a/OpenSSL/version.py b/OpenSSL/version.py
index 307dba0..eb3b736 100644
--- a/OpenSSL/version.py
+++ b/OpenSSL/version.py
@@ -6,4 +6,4 @@
 pyOpenSSL - A simple wrapper around the OpenSSL library
 """
 
-__version__ = '0.14'
+__version__ = '0.15.1'
diff --git a/README.rst b/README.rst
index 5b9f507..cac341f 100644
--- a/README.rst
+++ b/README.rst
@@ -1,14 +1,21 @@
 
 pyOpenSSL - A Python wrapper around the OpenSSL library
-------------------------------------------------------------------------------
+-------------------------------------------------------
 
-See the file INSTALL for installation instructions.
+.. image:: https://coveralls.io/repos/pyca/pyopenssl/badge.svg
+  :target: https://coveralls.io/r/pyca/pyopenssl
+
+.. image:: https://readthedocs.org/projects/pyopenssl/badge/?version=latest
+    :target: https://pyopenssl.readthedocs.org/
+    :alt: Latest Docs
+
+.. image:: https://travis-ci.org/pyca/pyopenssl.svg?branch=master
+    :target: https://travis-ci.org/pyca/pyopenssl
+
+See the file INSTALL.rst for installation instructions.
 
 See https://github.com/pyca/pyopenssl for development.
 
 See https://pyopenssl.readthedocs.org for documentation.
 
 See https://mail.python.org/mailman/listinfo/pyopenssl-users for the discussion mailing list.
-
-.. image:: https://coveralls.io/repos/pyca/pyopenssl/badge.png
-  :target: https://coveralls.io/r/pyca/pyopenssl
diff --git a/doc/api/crypto.rst b/doc/api/crypto.rst
index 237c7ae..43860ea 100644
--- a/doc/api/crypto.rst
+++ b/doc/api/crypto.rst
@@ -6,6 +6,117 @@
 .. py:module:: OpenSSL.crypto
    :synopsis: Generic cryptographic module
 
+
+.. py:data:: X509Type
+
+    See :py:class:`X509`.
+
+
+.. py:class:: X509()
+
+    A class representing X.509 certificates.
+
+
+.. py:data:: X509NameType
+
+    See :py:class:`X509Name`.
+
+
+.. py:class:: X509Name(x509name)
+
+    A class representing X.509 Distinguished Names.
+
+    This constructor creates a copy of *x509name* which should be an
+    instance of :py:class:`X509Name`.
+
+
+.. py:data:: X509ReqType
+
+    See :py:class:`X509Req`.
+
+
+.. py:class:: X509Req()
+
+    A class representing X.509 certificate requests.
+
+
+.. py:data:: X509StoreType
+
+    See :py:class:`X509Store`
+
+
+.. py:data:: X509Store
+
+    A class representing the X.509 store.
+
+
+.. py:data:: X509StoreContext
+
+    A class representing the X.509 store context.
+
+
+.. py:data:: PKeyType
+
+    See :py:class:`PKey`.
+
+
+.. py:class:: PKey()
+
+    A class representing DSA or RSA keys.
+
+.. py:data:: PKCS7Type
+
+    A Python type object representing the PKCS7 object type.
+
+
+.. py:data:: PKCS12Type
+
+    A Python type object representing the PKCS12 object type.
+
+
+.. py:data:: X509ExtensionType
+
+    See :py:class:`X509Extension`.
+
+
+.. py:class:: X509Extension(typename, critical, value[, subject][, issuer])
+
+    A class representing an X.509 v3 certificate extensions.  See
+    http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS for
+    *typename* strings and their options.  Optional parameters *subject* and
+    *issuer* must be X509 objects.
+
+
+.. py:data:: NetscapeSPKIType
+
+    See :py:class:`NetscapeSPKI`.
+
+
+.. py:class:: NetscapeSPKI([enc])
+
+    A class representing Netscape SPKI objects.
+
+    If the *enc* argument is present, it should be a base64-encoded string
+    representing a NetscapeSPKI object, as returned by the :py:meth:`b64_encode`
+    method.
+
+
+.. py:class:: CRL()
+
+    A class representing Certifcate Revocation List objects.
+
+
+.. py:class:: Revoked()
+
+    A class representing Revocation objects of CRL.
+
+
+.. py:data:: FILETYPE_PEM
+             FILETYPE_ASN1
+
+    File type constants.
+
+
 .. py:data:: TYPE_RSA
              TYPE_DSA
 
@@ -182,6 +293,35 @@
 .. autoclass:: X509Store
                :members:
 
+X509StoreContextError objects
+-----------------------------
+
+The X509StoreContextError is an exception raised from
+`X509StoreContext.verify_certificate` in circumstances where a certificate
+cannot be verified in a provided context.
+
+The certificate for which the verification error was detected is given by the
+``certificate`` attribute of the exception instance as a :class:`X509`
+instance.
+
+Details about the verification error are given in the exception's ``args`` attribute.
+
+
+X509StoreContext objects
+------------------------
+
+The X509StoreContext object is used for verifying a certificate against a set
+of trusted certificates.
+
+
+.. py:method:: X509StoreContext.verify_certificate()
+
+    Verify a certificate in the context of this initialized `X509StoreContext`.
+    On error, raises `X509StoreContextError`, otherwise does nothing.
+
+    .. versionadded:: 0.15
+
+
 .. _openssl-pkey:
 
 PKey objects
diff --git a/doc/api/ssl.rst b/doc/api/ssl.rst
index a75af1f..2929305 100644
--- a/doc/api/ssl.rst
+++ b/doc/api/ssl.rst
@@ -472,6 +472,53 @@
     .. versionadded:: 0.13
 
 
+.. py:method:: Context.set_npn_advertise_callback(callback)
+
+    Specify a callback function that will be called when offering `Next
+    Protocol Negotiation
+    <https://technotes.googlecode.com/git/nextprotoneg.html>`_ as a server.
+
+    *callback* should be the callback function.  It will be invoked with one
+    argument, the :py:class:`Connection` instance.  It should return a list of
+    bytestrings representing the advertised protocols, like
+    ``[b'http/1.1', b'spdy/2']``.
+
+    .. versionadded:: 0.15
+
+
+.. py:method:: Context.set_npn_select_callback(callback):
+
+    Specify a callback function that will be called when a server offers Next
+    Protocol Negotiation options.
+
+    *callback* should be the callback function.  It will be invoked with two
+    arguments: the :py:class:`Connection`, and a list of offered protocols as
+    bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``.  It should return one of
+    those bytestrings, the chosen protocol.
+
+    .. versionadded:: 0.15
+
+.. py:method:: Context.set_alpn_protos(protos)
+
+    Specify the protocols that the client is prepared to speak after the TLS
+    connection has been negotiated using Application Layer Protocol
+    Negotiation.
+
+    *protos* should be a list of protocols that the client is offering, each
+    as a bytestring. For example, ``[b'http/1.1', b'spdy/2']``.
+
+
+.. py:method:: Context.set_alpn_select_callback(callback)
+
+    Specify a callback function that will be called on the server when a client
+    offers protocols using Application Layer Protocol Negotiation.
+
+    *callback* should be the callback function. It will be invoked with two
+    arguments: the :py:class:`Connection` and a list of offered protocols as
+    bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``. It should return one of
+    these bytestrings, the chosen protocol.
+
+
 .. _openssl-session:
 
 Session objects
@@ -614,6 +661,14 @@
     by *bufsize*.
 
 
+.. py:method:: Connection.recv_into(buffer[, nbytes[, flags]])
+
+    Receive data from the Connection and copy it directly into the provided
+    buffer. The return value is the number of bytes read from the connection.
+    The maximum amount of data to be received at once is specified by *nbytes*.
+    *flags* is accepted for compatibility with ``socket.recv_into`` but its
+    value is ignored.
+
 .. py:method:: Connection.bio_write(bytes)
 
     If the Connection was created with a memory BIO, this method can be used to add
@@ -806,6 +861,31 @@
     .. versionadded:: 0.15
 
 
+.. py:method:: Connection.get_next_proto_negotiated():
+
+    Get the protocol that was negotiated by Next Protocol Negotiation. Returns
+    a bytestring of the protocol name. If no protocol has been negotiated yet,
+    returns an empty string.
+
+    .. versionadded:: 0.15
+
+.. py:method:: Connection.set_alpn_protos(protos)
+
+    Specify the protocols that the client is prepared to speak after the TLS
+    connection has been negotiated using Application Layer Protocol
+    Negotiation.
+
+    *protos* should be a list of protocols that the client is offering, each
+    as a bytestring. For example, ``[b'http/1.1', b'spdy/2']``.
+
+
+.. py:method:: Connection.get_alpn_proto_negotiated()
+
+    Get the protocol that was negotiated by Application Layer Protocol
+    Negotiation. Returns a bytestring of the protocol name. If no protocol has
+    been negotiated yet, returns an empty string.
+
+
 .. Rubric:: Footnotes
 
 .. [#connection-context-socket] Actually, all that is required is an object that
diff --git a/doc/conf.py b/doc/conf.py
index 5dc2bd9..5a1940b 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -51,9 +51,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.14'
+version = '0.15.1'
 # The full version, including alpha/beta/rc tags.
-release = '0.14'
+release = version
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -123,7 +123,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+# html_static_path = ['_static']
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
diff --git a/setup.py b/setup.py
index 3d3fe04..c4fbbd5 100755
--- a/setup.py
+++ b/setup.py
@@ -1,17 +1,42 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) Jean-Paul Calderone 2008-2014, All rights reserved
+# Copyright (C) Jean-Paul Calderone 2008-2015, All rights reserved
 #
 
 """
 Installation script for the OpenSSL module
 """
 
+import sys
+
 from setuptools import setup
+from setuptools.command.test import test as TestCommand
+
 
 # XXX Deduplicate this
-__version__ = '0.14'
+__version__ = '0.15.1'
+
+
+class PyTest(TestCommand):
+    user_options = [("pytest-args=", "a", "Arguments to pass to py.test")]
+
+    def initialize_options(self):
+        TestCommand.initialize_options(self)
+        self.pytest_args = None
+
+    def finalize_options(self):
+        TestCommand.finalize_options(self)
+        self.test_args = []
+        self.test_suite = True
+
+    def run_tests(self):
+        # import here, cause outside the eggs aren't loaded
+        import pytest
+        errno = pytest.main(self.pytest_args or [] +
+                            ["OpenSSL"])
+        sys.exit(errno)
+
 
 setup(name='pyOpenSSL', version=__version__,
       packages = ['OpenSSL'],
@@ -26,7 +51,9 @@
                      'OpenSSL.test.util',
                      'OpenSSL.test.test_crypto',
                      'OpenSSL.test.test_rand',
-                     'OpenSSL.test.test_ssl'],
+                     'OpenSSL.test.test_ssl',
+                     'OpenSSL.test.test_tsafe',
+                     'OpenSSL.test.test_util',],
       description = 'Python wrapper module around the OpenSSL library',
       author = 'Jean-Paul Calderone',
       author_email = 'exarkun@twistedmatrix.com',
@@ -34,7 +61,7 @@
       maintainer_email = 'exarkun@twistedmatrix.com',
       url = 'https://github.com/pyca/pyopenssl',
       license = 'APL2',
-      install_requires=["cryptography>=0.4", "six>=1.5.2"],
+      install_requires=["cryptography>=0.7", "six>=1.5.2"],
       long_description = """\
 High-level wrapper around a subset of the OpenSSL library, includes
  * SSL.Connection objects, wrapping the methods of Python's portable
@@ -72,4 +99,10 @@
         'Topic :: Software Development :: Libraries :: Python Modules',
         'Topic :: System :: Networking',
         ],
-      test_suite="OpenSSL")
+      test_suite="OpenSSL",
+      tests_require=[
+          "pytest",
+      ],
+      cmdclass={
+          "test": PyTest,
+      })
diff --git a/tox.ini b/tox.ini
index 67386d1..da54916 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,15 @@
 [tox]
-envlist = pypy,py26,py27,py32,py33
+envlist = pypy,py26,py27,py32,py33,py34
 
 [testenv]
+deps =
+    setuptools>=7.0  # older setuptools pollute CWD with egg files of dependencies
+    coverage
 setenv =
     # Do not allowed the executing environment to pollute the test environment
     # with extra packages.
     PYTHONPATH=
-# The standard library unittest module can run tests on Python 2.7 and newer
-commands = python setup.py test
+commands =
+    python -c "import OpenSSL.SSL; print(OpenSSL.SSL.SSLeay_version(OpenSSL.SSL.SSLEAY_VERSION))"
+    coverage run --branch --source=OpenSSL setup.py test
+    coverage report -m