Beispiel #1
0
    def handshakeSupported(self):
        '''Verify the current connection supports a V3 handshake.

        .. note:: See tor-spec, Section 2 for details.

        :returns: **bool** **True** if at least one of the conditions
            necessary for V3 support is **True** for this connection,
            **False** otherwise
        '''
        conn_cert = self.transport.getPeerCertificate()
        issuer = conn_cert.get_issuer()
        subject = conn_cert.get_subject()
        supported = False

        # The certificate is self-signed
        supported |= crypto_util.verifyCertSig(conn_cert, conn_cert)
        # Some component other than "commonName" is set in the subject or
        # issuer DN of the certificate.
        supported |= len(issuer.get_components()) > 1
        supported |= len(subject.get_components()) > 1
        # The commonName of the subject or issuer of the certificate ends
        # with a suffix other than ".net".
        supported |= issuer.commonName.split('.')[-1] != 'net'
        supported |= subject.commonName.split('.')[-1] != 'net'
        # The certificate's public key modulus is longer than 1024 bits.
        supported |= conn_cert.get_pubkey().bits() > V3_KEY_BITS

        return supported
Beispiel #2
0
    def _processCertsCell(self, cell):
        if not isinstance(cell, CertsCell):
            msg = ("Connection to {} received a {} cell, expected a "
                   "CertsCell.".format(self.micro_status_entry.fingerprint,
                                       type(cell)))
            raise TypeError(msg)

        link_cert, id_cert = _getCertsFromCell(cell)

        if not _certsHaveValidTime([link_cert, id_cert]):
            msg = ("Certificates sent by {} do not have a valid time. "
                   "Destroying the connection."
                   .format(self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not _ASN1KeysEqual(link_cert.get_pubkey(),
                              self._connection_cert.get_pubkey()):
            msg = ("The public key used for the TLS connection to {} is not "
                   "the same key given in the link certificate in the "
                   "CertsCell. Destroying the connection."
                   .format(self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not _isRSA1024BitKey(id_cert.get_pubkey()):
            msg = ("The public key in the ID certificate sent by relay {} "
                   "in the CertsCell is not a 1024-bit RSA key. Destroying "
                   "the connection."
                   .format(self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not crypto.verifyCertSig(id_cert, link_cert):
            msg = ("The link certificate is not properly signed by the "
                   "ID certificate sent by {} in a CertsCell. Destroying "
                   "the connection."
                   .format(self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not crypto.verifyCertSig(id_cert, id_cert):
            msg = ("The ID certificate sent in a CertsCell by {} is not "
                   "properly self-signed. Destroying the connection."
                   .format(self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        return self._recvCell()
Beispiel #3
0
    def _processCertsCell(self, cell):
        if not isinstance(cell, CertsCell):
            msg = ("Connection to {} received a {} cell, expected a "
                   "CertsCell.".format(self.micro_status_entry.fingerprint,
                                       type(cell)))
            raise TypeError(msg)

        link_cert, id_cert = _getCertsFromCell(cell)

        if not _certsHaveValidTime([link_cert, id_cert]):
            msg = ("Certificates sent by {} do not have a valid time. "
                   "Destroying the connection.".format(
                       self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not _ASN1KeysEqual(link_cert.get_pubkey(),
                              self._connection_cert.get_pubkey()):
            msg = ("The public key used for the TLS connection to {} is not "
                   "the same key given in the link certificate in the "
                   "CertsCell. Destroying the connection.".format(
                       self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not _isRSA1024BitKey(id_cert.get_pubkey()):
            msg = ("The public key in the ID certificate sent by relay {} "
                   "in the CertsCell is not a 1024-bit RSA key. Destroying "
                   "the connection.".format(
                       self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not crypto.verifyCertSig(id_cert, link_cert):
            msg = ("The link certificate is not properly signed by the "
                   "ID certificate sent by {} in a CertsCell. Destroying "
                   "the connection.".format(
                       self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        if not crypto.verifyCertSig(id_cert, id_cert):
            msg = ("The ID certificate sent in a CertsCell by {} is not "
                   "properly self-signed. Destroying the connection.".format(
                       self.micro_status_entry.fingerprint))
            raise ValueError(msg)

        return self._recvCell()
Beispiel #4
0
    def test_verifyCertSig_yes_sha256(self, mock_cv,  mock_do, mock_ds, mock_dc):
        mock_dseq = mock.MagicMock()
        mock_dseq.__getitem__.return_value = 'd'
        mock_dseq.decode = mock.Mock()
        mock_ds.return_value = mock_dseq
        mock_derobj = mock.Mock()
        mock_derobj.payload = '\x00payload'
        mock_do.return_value = mock_derobj

        ret = util.verifyCertSig('idcert', 'verifycert', algo='sha256')

        mock_dc.assert_called_once_with(OpenSSL.crypto.FILETYPE_ASN1, 'verifycert')
        mock_dseq.decode.assert_called_once_with('asn1cert')
        self.assertEqual(mock_ds.call_count, 1)
        self.assertEqual(mock_do.call_count, 1)
        mock_cv.assert_called_once_with('idcert', 'payload', 'd', 'sha256')
        self.assertTrue(ret)
Beispiel #5
0
    def test_verifyCertSig_not_reserved(self, mock_cv,  mock_do, mock_ds, mock_dc):
        mock_dseq = mock.MagicMock()
        mock_dseq.__getitem__.return_value = 'd'
        mock_dseq.decode = mock.Mock()
        mock_ds.return_value = mock_dseq
        mock_derobj = mock.Mock()
        mock_derobj.payload = '\x01payload'
        mock_do.return_value = mock_derobj

        ret = util.verifyCertSig('idcert', 'verifycert')

        mock_dc.assert_called_once_with(OpenSSL.crypto.FILETYPE_ASN1, 'verifycert')
        mock_dseq.decode.assert_called_once_with('asn1cert')
        self.assertEqual(mock_ds.call_count, 1)
        self.assertEqual(mock_do.call_count, 1)
        self.assertEqual(mock_cv.call_count, 0)
        self.assertFalse(ret)
Beispiel #6
0
    def test_verifyCertSig_no(self, mock_cv, mock_do, mock_ds, mock_dc):
        mock_dseq = mock.MagicMock()
        mock_dseq.__getitem__.return_value = 'd'
        mock_dseq.decode = mock.Mock()
        mock_ds.return_value = mock_dseq
        mock_derobj = mock.Mock()
        mock_derobj.payload = '\x00payload'
        mock_do.return_value = mock_derobj

        ret = util.verifyCertSig('idcert', 'verifycert')

        mock_dc.assert_called_once_with(OpenSSL.crypto.FILETYPE_ASN1,
                                        'verifycert')
        mock_dseq.decode.assert_called_once_with('asn1cert')
        self.assertEqual(mock_ds.call_count, 1)
        self.assertEqual(mock_do.call_count, 1)
        mock_cv.assert_called_once_with('idcert', 'payload', 'd', 'sha1')
        self.assertFalse(ret)
Beispiel #7
0
def _connectionSupportsHandshake(cert):
    supported = False

    issuer = cert.get_issuer()
    subject = cert.get_subject()

    # The certificate is self-signed
    supported |= crypto.verifyCertSig(cert, cert)
    # Some component other than "commonName" ("CN") is set in the subject or
    # issuer DN of the certificate.
    supported |= bool([f for f in issuer.get_components() if f[0] != "CN"])
    supported |= bool([f for f in subject.get_components() if f[0] != "CN"])
    # The commonName of the subject or issuer of the certificate ends
    # with a suffix other than ".net".
    supported |= issuer.commonName.split('.')[-1] != 'net'
    supported |= subject.commonName.split('.')[-1] != 'net'
    # The certificate's public key modulus is longer than 1024 bits.
    supported |= cert.get_pubkey().bits() > V3_KEY_BITS

    return supported
Beispiel #8
0
def _connectionSupportsHandshake(cert):
    supported = False

    issuer = cert.get_issuer()
    subject = cert.get_subject()

    # The certificate is self-signed
    supported |= crypto.verifyCertSig(cert, cert)
    # Some component other than "commonName" ("CN") is set in the subject or
    # issuer DN of the certificate.
    supported |= bool([f for f in issuer.get_components() if f[0] != "CN"])
    supported |= bool([f for f in subject.get_components() if f[0] != "CN"])
    # The commonName of the subject or issuer of the certificate ends
    # with a suffix other than ".net".
    supported |= issuer.commonName.split('.')[-1] != 'net'
    supported |= subject.commonName.split('.')[-1] != 'net'
    # The certificate's public key modulus is longer than 1024 bits.
    supported |= cert.get_pubkey().bits() > V3_KEY_BITS

    return supported
Beispiel #9
0
    def _processCerts(self, cell):
        '''Process an incoming cell when we're in the V3State.EXPECT_CERTS
        state.

        Verify that we did receive a valid Certs cell and the certificates
        satisfy V3 criteria.

        .. note:: See tor-spec, Section 4.2 for details.

        :param cell cell: incoming cell
        '''
        V3FSM._verifyCellCmd(cell.header.cmd, CERTS_CMD)

        if cell.num_certs != 2:
            msg = 'Unexpected number of certificates in Certs cell: {0}'
            raise HandshakeFailed(msg.format(cell.num_certs))

        id_cert = None
        link_cert = None

        # The CERTS cell contains exactly one CertType 1 "Link" certificate.
        # The CERTS cell contains exactly one CertType 2 "ID" certificate.
        LINK_CERT_TYPE = 1
        ID_CERT_TYPE = 2

        for i in xrange(cell.num_certs):
            cert_item = cell.cert_payload_items[i]
            ctype = cert_item.cert_type

            if ctype != LINK_CERT_TYPE and ctype != ID_CERT_TYPE:
                msg = 'Unexpected certificate type in Certs cell: {0}'
                raise HandshakeFailed(msg.format(ctype))

            cert = ssl.DER_cert_to_PEM_cert(cert_item.cert)

            if ctype == LINK_CERT_TYPE:
                link_cert = SSLCrypto.load_certificate(SSLCrypto.FILETYPE_PEM,
                                                       cert)
            else:
                id_cert = SSLCrypto.load_certificate(SSLCrypto.FILETYPE_PEM,
                                                     cert)

        if id_cert is None:
            raise HandshakeFailed('Certs cell missing ID certificate')
        if link_cert is None:
            raise HandshakeFailed('Certs cell missing ID certificate')

        conn_cert = self.transport.getPeerCertificate()

        idKey = id_cert.get_pubkey()
        linkKey = link_cert.get_pubkey()
        connKey = conn_cert.get_pubkey()

        # Both certificates have good validAfter and validUntil dates
        if crypto_util.validCertTime(link_cert) is False:
            msg = "Link certificate has an invalid 'validAfter' or "
            msg += "'validUntil' time."
            raise HandshakeFailed(msg)

        if crypto_util.validCertTime(id_cert) is False:
            msg = "ID certificate has an invalid 'validAfter' or "
            msg += "'validUntil' time."
            raise HandshakeFailed(msg)

        # The certified key in the Link certificate matches the
        # link key that was used to negotiate the TLS connection.
        linkASN1Key = SSLCrypto.dump_privatekey(SSLCrypto.FILETYPE_ASN1,
                                                linkKey)
        connASN1Key = SSLCrypto.dump_privatekey(SSLCrypto.FILETYPE_ASN1,
                                                connKey)
        if linkASN1Key != connASN1Key:
            msg = 'Public key from Link certificate is different from the key'
            msg += 'used to initiate the TLS connection'
            raise HandshakeFailed(msg)

        # The certified key in the ID certificate is a 1024-bit RSA key.
        if idKey.type() != OPENSSL_RSA_KEY_TYPE:
            msg = 'ID certificate key is not RSA. Type: {0}'
            raise HandshakeFailed(msg.format(idKey.type()))
        if idKey.bits() != V3_KEY_BITS:
            msg = 'ID certificate is not 1024 bits. Bits: {0}'
            raise HandshakeFailed(msg.format(idKey.bits()))

        # verify id_cert has properly signed link_cert
        if crypto_util.verifyCertSig(id_cert, link_cert) is not True:
            msg = 'ID certificate has not properly signed Link certificate'
            raise HandshakeFailed(msg)
        # verify id_cert is properly self-signed
        if crypto_util.verifyCertSig(id_cert, id_cert) is not True:
            msg = 'ID certificate is not properly self-signed.'
            raise HandshakeFailed(msg)

        self._state = V3State.EXPECT_AUTH_CHALLENGE
        return None