Merge pull request #2534 from alex/ev-oid

Fixed #2531 -- added missing EV oid
diff --git a/.travis/install.sh b/.travis/install.sh
index 112add2..142b498 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -34,8 +34,8 @@
             pyenv global 3.4.2
             ;;
         py35)
-            pyenv install 3.5.0
-            pyenv global 3.5.0
+            pyenv install 3.5.1
+            pyenv global 3.5.1
             ;;
         pypy)
             pyenv install pypy-4.0.1
diff --git a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
index 3d2c25b..b236d77 100644
--- a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
+++ b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
@@ -6,7 +6,7 @@
 from cryptography.hazmat.primitives import hashes
 from cryptography.hazmat.primitives.asymmetric import ec
 from cryptography.hazmat.primitives.asymmetric.utils import (
-    encode_rfc6979_signature
+    encode_dss_signature
 )
 
 from tests.utils import (
@@ -27,7 +27,7 @@
     message = vector['message']
     x = vector['x']
     y = vector['y']
-    signature = encode_rfc6979_signature(vector['r'], vector['s'])
+    signature = encode_dss_signature(vector['r'], vector['s'])
 
     numbers = ec.EllipticCurvePublicNumbers(
         x, y,
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 768559c..e69554f 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -40,6 +40,7 @@
     _Certificate, _CertificateRevocationList, _CertificateSigningRequest,
     _DISTPOINT_TYPE_FULLNAME, _DISTPOINT_TYPE_RELATIVENAME
 )
+from cryptography.hazmat.bindings._openssl import ffi as _ffi
 from cryptography.hazmat.bindings.openssl import binding
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@@ -625,6 +626,34 @@
 }
 
 
+class _PasswordUserdata(object):
+    def __init__(self, password):
+        self.password = password
+        self.called = 0
+        self.exception = None
+
+
+def _pem_password_cb(buf, size, writing, userdata_handle):
+    ud = _ffi.from_handle(userdata_handle)
+    ud.called += 1
+
+    if not ud.password:
+        ud.exception = TypeError(
+            "Password was not given but private key is encrypted."
+        )
+        return -1
+    elif len(ud.password) < size:
+        pw_buf = _ffi.buffer(buf, size)
+        pw_buf[:len(ud.password)] = ud.password
+        return len(ud.password)
+    else:
+        ud.exception = ValueError(
+            "Passwords longer than {0} bytes are not supported "
+            "by this backend.".format(size - 1)
+        )
+        return 0
+
+
 @utils.register_interface(CipherBackend)
 @utils.register_interface(CMACBackend)
 @utils.register_interface(DERSerializationBackend)
@@ -1090,37 +1119,22 @@
 
         Useful for decrypting PKCS8 files and so on.
 
-        Returns a tuple of (cdata function pointer, callback function).
+        Returns a tuple of (cdata function pointer, userdata).
         """
+        # Forward compatibility for new static callbacks:
+        # _pem_password_cb is not a nested function because closures don't
+        # work well with static callbacks. Static callbacks are registered
+        # globally. The backend is passed in as userdata argument.
 
-        def pem_password_cb(buf, size, writing, userdata):
-            pem_password_cb.called += 1
+        userdata = _PasswordUserdata(password=password)
 
-            if not password:
-                pem_password_cb.exception = TypeError(
-                    "Password was not given but private key is encrypted."
-                )
-                return 0
-            elif len(password) < size:
-                pw_buf = self._ffi.buffer(buf, size)
-                pw_buf[:len(password)] = password
-                return len(password)
-            else:
-                pem_password_cb.exception = ValueError(
-                    "Passwords longer than {0} bytes are not supported "
-                    "by this backend.".format(size - 1)
-                )
-                return 0
-
-        pem_password_cb.called = 0
-        pem_password_cb.exception = None
-
-        return (
-            self._ffi.callback("int (char *, int, int, void *)",
-                               pem_password_cb),
-            pem_password_cb
+        pem_password_cb = self._ffi.callback(
+            "int (char *, int, int, void *)",
+            _pem_password_cb,
         )
 
+        return pem_password_cb, userdata
+
     def _mgf1_hash_supported(self, algorithm):
         if self._lib.Cryptography_HAS_MGF1_MD:
             return self.hash_supported(algorithm)
@@ -1626,31 +1640,32 @@
     def _load_key(self, openssl_read_func, convert_func, data, password):
         mem_bio = self._bytes_to_bio(data)
 
-        password_callback, password_func = self._pem_password_cb(password)
+        password_cb, userdata = self._pem_password_cb(password)
+        userdata_handle = self._ffi.new_handle(userdata)
 
         evp_pkey = openssl_read_func(
             mem_bio.bio,
             self._ffi.NULL,
-            password_callback,
-            self._ffi.NULL
+            password_cb,
+            userdata_handle,
         )
 
         if evp_pkey == self._ffi.NULL:
-            if password_func.exception is not None:
+            if userdata.exception is not None:
                 errors = self._consume_errors()
                 self.openssl_assert(errors)
-                raise password_func.exception
+                raise userdata.exception
             else:
                 self._handle_key_loading_error()
 
         evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
 
-        if password is not None and password_func.called == 0:
+        if password is not None and userdata.called == 0:
             raise TypeError(
                 "Password was given but private key is not encrypted.")
 
         assert (
-            (password is not None and password_func.called == 1) or
+            (password is not None and userdata.called == 1) or
             password is None
         )
 
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
index 98a61e0..7b4df1c 100644
--- a/src/cryptography/x509/oid.py
+++ b/src/cryptography/x509/oid.py
@@ -12,6 +12,35 @@
     def __init__(self, dotted_string):
         self._dotted_string = dotted_string
 
+        nodes = self._dotted_string.split(".")
+        intnodes = []
+
+        # There must be at least 2 nodes, the first node must be 0..2, and
+        # if less than 2, the second node cannot have a value outside the
+        # range 0..39.  All nodes must be integers.
+        for node in nodes:
+            try:
+                intnodes.append(int(node, 0))
+            except ValueError:
+                raise ValueError(
+                    "Malformed OID: %s (non-integer nodes)" % (
+                        self._dotted_string))
+
+        if len(nodes) < 2:
+            raise ValueError(
+                "Malformed OID: %s (insufficient number of nodes)" % (
+                    self._dotted_string))
+
+        if intnodes[0] > 2:
+            raise ValueError(
+                "Malformed OID: %s (first node outside valid range)" % (
+                    self._dotted_string))
+
+        if intnodes[0] < 2 and intnodes[1] >= 40:
+            raise ValueError(
+                "Malformed OID: %s (second node outside valid range)" % (
+                    self._dotted_string))
+
     def __eq__(self, other):
         if not isinstance(other, ObjectIdentifier):
             return NotImplemented
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 8533159..d048fe6 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -503,8 +503,21 @@
 
 class TestOpenSSLSerialisationWithOpenSSL(object):
     def test_pem_password_cb_buffer_too_small(self):
-        ffi_cb, cb = backend._pem_password_cb(b"aa")
-        assert cb(None, 1, False, None) == 0
+        ffi_cb, userdata = backend._pem_password_cb(b"aa")
+        handle = backend._ffi.new_handle(userdata)
+        buf = backend._ffi.new('char *')
+        assert ffi_cb(buf, 1, False, handle) == 0
+        assert userdata.called == 1
+        assert isinstance(userdata.exception, ValueError)
+
+    def test_pem_password_cb(self):
+        password = b'abcdefg'
+        ffi_cb, userdata = backend._pem_password_cb(password)
+        handle = backend._ffi.new_handle(userdata)
+        buf = backend._ffi.new('char *')
+        assert ffi_cb(buf, len(password) + 1, False, handle) == len(password)
+        assert userdata.called == 1
+        assert backend._ffi.string(buf, len(password)) == password
 
     def test_unsupported_evp_pkey_type(self):
         key = pretend.stub(type="unsupported")
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index a0417fb..8613267 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -19,7 +19,7 @@
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.primitives.asymmetric import ec
 from cryptography.hazmat.primitives.asymmetric.utils import (
-    encode_rfc6979_signature
+    encode_dss_signature
 )
 
 from .fixtures_ec import EC_KEY_SECP384R1
@@ -434,7 +434,7 @@
             curve_type()
         ).public_key(backend)
 
-        signature = encode_rfc6979_signature(vector['r'], vector['s'])
+        signature = encode_dss_signature(vector['r'], vector['s'])
 
         verifier = key.verifier(
             signature,
@@ -463,7 +463,7 @@
             curve_type()
         ).public_key(backend)
 
-        signature = encode_rfc6979_signature(vector['r'], vector['s'])
+        signature = encode_dss_signature(vector['r'], vector['s'])
 
         verifier = key.verifier(
             signature,
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 86f771b..67066f0 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -3210,15 +3210,15 @@
     def test_init_bad_value(self):
         with pytest.raises(TypeError):
             x509.NameAttribute(
-                x509.ObjectIdentifier('oid'),
+                x509.ObjectIdentifier('2.999.1'),
                 b'bytes'
             )
 
     def test_eq(self):
         assert x509.NameAttribute(
-            x509.ObjectIdentifier('oid'), u'value'
+            x509.ObjectIdentifier('2.999.1'), u'value'
         ) == x509.NameAttribute(
-            x509.ObjectIdentifier('oid'), u'value'
+            x509.ObjectIdentifier('2.999.1'), u'value'
         )
 
     def test_ne(self):
@@ -3228,12 +3228,12 @@
             x509.ObjectIdentifier('2.5.4.5'), u'value'
         )
         assert x509.NameAttribute(
-            x509.ObjectIdentifier('oid'), u'value'
+            x509.ObjectIdentifier('2.999.1'), u'value'
         ) != x509.NameAttribute(
-            x509.ObjectIdentifier('oid'), u'value2'
+            x509.ObjectIdentifier('2.999.1'), u'value2'
         )
         assert x509.NameAttribute(
-            x509.ObjectIdentifier('oid'), u'value'
+            x509.ObjectIdentifier('2.999.2'), u'value'
         ) != object()
 
     def test_repr(self):
@@ -3252,64 +3252,87 @@
 
 class TestObjectIdentifier(object):
     def test_eq(self):
-        oid1 = x509.ObjectIdentifier('oid')
-        oid2 = x509.ObjectIdentifier('oid')
+        oid1 = x509.ObjectIdentifier('2.999.1')
+        oid2 = x509.ObjectIdentifier('2.999.1')
         assert oid1 == oid2
 
     def test_ne(self):
-        oid1 = x509.ObjectIdentifier('oid')
-        assert oid1 != x509.ObjectIdentifier('oid1')
+        oid1 = x509.ObjectIdentifier('2.999.1')
+        assert oid1 != x509.ObjectIdentifier('2.999.2')
         assert oid1 != object()
 
     def test_repr(self):
         oid = x509.ObjectIdentifier("2.5.4.3")
         assert repr(oid) == "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>"
-        oid = x509.ObjectIdentifier("oid1")
-        assert repr(oid) == "<ObjectIdentifier(oid=oid1, name=Unknown OID)>"
+        oid = x509.ObjectIdentifier("2.999.1")
+        assert repr(oid) == "<ObjectIdentifier(oid=2.999.1, name=Unknown OID)>"
 
     def test_name_property(self):
         oid = x509.ObjectIdentifier("2.5.4.3")
         assert oid._name == 'commonName'
-        oid = x509.ObjectIdentifier("oid1")
+        oid = x509.ObjectIdentifier("2.999.1")
         assert oid._name == 'Unknown OID'
 
+    def test_too_short(self):
+        with pytest.raises(ValueError):
+            x509.ObjectIdentifier("1")
+
+    def test_invalid_input(self):
+        with pytest.raises(ValueError):
+            x509.ObjectIdentifier("notavalidform")
+
+    def test_invalid_node1(self):
+        with pytest.raises(ValueError):
+            x509.ObjectIdentifier("7.1.37")
+
+    def test_invalid_node2(self):
+        with pytest.raises(ValueError):
+            x509.ObjectIdentifier("1.50.200")
+
+    def test_valid(self):
+        x509.ObjectIdentifier("0.35.200")
+        x509.ObjectIdentifier("1.39.999")
+        x509.ObjectIdentifier("2.5.29.3")
+        x509.ObjectIdentifier("2.999.37.5.22.8")
+        x509.ObjectIdentifier("2.25.305821105408246119474742976030998643995")
+
 
 class TestName(object):
     def test_eq(self):
         name1 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
         ])
         name2 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
         ])
         assert name1 == name2
 
     def test_ne(self):
         name1 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
         ])
         name2 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
         ])
         assert name1 != name2
         assert name1 != object()
 
     def test_hash(self):
         name1 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
         ])
         name2 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
         ])
         name3 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2'),
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'),
         ])
 
         assert hash(name1) == hash(name2)
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index 8f46936..751de08 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -18,7 +18,8 @@
 )
 from cryptography.hazmat.primitives.asymmetric import ec
 from cryptography.x509.oid import (
-    AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, NameOID
+    AuthorityInformationAccessOID, ExtendedKeyUsageOID,
+    ExtensionOID, NameOID
 )
 
 from .hazmat.primitives.test_ec import _skip_curve_unsupported
@@ -603,8 +604,14 @@
     def test_authority_cert_serial_number_not_integer(self):
         dirname = x509.DirectoryName(
             x509.Name([
-                x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-                x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+                x509.NameAttribute(
+                    x509.ObjectIdentifier('2.999.1'),
+                    u'value1'
+                ),
+                x509.NameAttribute(
+                    x509.ObjectIdentifier('2.999.2'),
+                    u'value2'
+                ),
             ])
         )
         with pytest.raises(TypeError):
@@ -617,8 +624,14 @@
     def test_authority_issuer_not_none_serial_none(self):
         dirname = x509.DirectoryName(
             x509.Name([
-                x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1'),
-                x509.NameAttribute(x509.ObjectIdentifier('oid2'), u'value2'),
+                x509.NameAttribute(
+                    x509.ObjectIdentifier('2.999.1'),
+                    u'value1'
+                ),
+                x509.NameAttribute(
+                    x509.ObjectIdentifier('2.999.2'),
+                    u'value2'
+                ),
             ])
         )
         with pytest.raises(ValueError):
@@ -1166,10 +1179,10 @@
 
     def test_eq(self):
         name = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1')
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1')
         ])
         name2 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1')
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1')
         ])
         gn = x509.DirectoryName(x509.Name([name]))
         gn2 = x509.DirectoryName(x509.Name([name2]))
@@ -1177,10 +1190,10 @@
 
     def test_ne(self):
         name = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value1')
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1')
         ])
         name2 = x509.Name([
-            x509.NameAttribute(x509.ObjectIdentifier('oid'), u'value2')
+            x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2')
         ])
         gn = x509.DirectoryName(x509.Name([name]))
         gn2 = x509.DirectoryName(x509.Name([name2]))