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
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()
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()
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)
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)
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)
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
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