SSL-Verbindungen mit pyopenssl

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Ich habe mich mal ein wenig mit pyopenssl beschaeftigt, welches ein duenner Wrapper um OpenSSL ist.

Hier ein einfacher SSL-Client:

Code: Alles auswählen

from OpenSSL import SSL, crypto
import socket

HOST = "www.example.com"
PORT = 443
PAGE = "/index.html"

def verify_cb(conn, cert, errnum, depth, ok):
    print "Got certificate: %s" % cert.get_subject()
    print "Issued by: %s" % cert.get_issuer()
    return ok

keystore = crypto.load_pkcs12(open("userkey.p12").read(), "geheim")

# Initialise SSL context:
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_verify(SSL.VERIFY_PEER, verify_cb) # Demand a server certificate
ctx.load_verify_locations("server-ca-cert.pem")
ctx.use_privatekey(keystore.get_privatekey())
ctx.use_certificate(keystore.get_certificate())

# Set up client:
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.connect((HOST, PORT))
sock.write("GET %s HTTP/1.0\nHost: %s\n\n" % (PAGE, HOST))

# Read response:
while True:
    try:
        print sock.recv(4096)
    except SSL.ZeroReturnError:
        break
Ab Zeile 16 wird der SSL-Context initialisiert, der bestimmt, wie sich die SSL-Verbindung verhalten soll. Fuer eine anonyme SSL-Verbindung fuer reine Verschluesselung reicht Zeile 16 aus.

In Zeile 17 wird angegeben, dass das Zertifikat vom Server angefragt und gecheckt werden soll. verify_cb gibt eine Callack-Funktion an, die nach jedem Zertifikats-Check (fuer jedes Zertifikat in der Certificate Chain) ausgefuehrt wird, Zeilen 8 bis 11.

Zeile 18 laedt das CA-Zertifikat, mit dem das Server-Zertifkat geprueft werden soll.

Fuer viele https-Verbindungen reichen diese Angaben schon aus; benoetigt man jedoch ein User-Zertifikat, um sich beim Server zu authentifizieren, so muss man den privaten und oeffentlichen Schluessel laden, siehe Zeile 19 und 20. Diese beiden Funktionen nehmen nur das pem-Format. Meist liegt das private/public key pair in einen pkcs12-Format vor, solch einen Keystore kann man mit dem crypto-Modul von pyopenssl laden (Zeile 12) und sich dann die beiden Schluessel ins pem-Format umwandeln lassen.

Der ssl-Socket, der in Zeile 23 erzeugt wird, laesst sich jetzt wie ein ganz normaler Socket verwenden.

Ein SSL-Server funktioniert ganz genau so, nur dass man ab Zeile 24 die gewoehnlichen Befehle fuer einen Server-Socket absetzt:

Code: Alles auswählen

# Set up sever:
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((HOST, PORT))
sock.listen(1)
print "Waiting for connections."

#Wait for clients to connect:
(conn, address) = sock.accept()
print "Got connection from %s: %s" % address

while True:
    try:
        print conn.recv(4096)
    except SSL.ZeroReturnError:
        break
Als naechstest stellt sich natuerlich die Frage, wie man das mit schon vorhandenen Bibliotheken wie httplib, xmlrpc und soappy zusammenbringt... :D
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Ich wollte Anhand deines Beispiels eine nur verschlüsselte Verbindung herstellen, bekomme aber immer Fehler.

Client:

Code: Alles auswählen

import socket
from OpenSSL import SSL

ctx = SSL.Context(SSL.TLSv1_METHOD)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))

sock.connect(('localhost', 10000))
sock.write("Hallo")
sock.recv(4096)
sock.close()
Server:

Code: Alles auswählen

import socket
from OpenSSL import SSL 

ctx = SSL.Context(SSL.TLSv1_METHOD)
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('localhost', 10000))
sock.listen(1)

print "Waiting for connections."
(conn, address) = sock.accept()
print "Got connection from %s: %s" % address

conn.recv(4096)
conn.write('Bye')
conn.close()

sock.close()
Fehlermeldung Server:

Code: Alles auswählen

Waiting for connections.
Got connection from 127.0.0.1: 52576
Traceback (most recent call last):
  File "H:\Projects\_pySC\ssl\server.py", line 14, in <module>
    conn.recv(4096)
OpenSSL.SSL.Error: [('SSL routines', 'SSL3_GET_CLIENT_HELLO', 'no shared cipher')]
Fehlermeldung Client:

Code: Alles auswählen

Traceback (most recent call last):
  File "H:\Projects\_pySC\ssl\test.py", line 8, in <module>
    sock.write("Hallo")
OpenSSL.SSL.Error: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert handshake failure'), ('SSL routines', 'SSL3_WRITE_BYTES', 'ssl handshake failure')]
Was mache ich falsch?

Gruss
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Genau das Problem habe ich auch nie geloest: http://www.python-forum.de/topic-10279.html
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Vermutlich benötigt dein SSL-Server eine Authentifizierung, du benützt aber nur Chiffren, mit denen keine Authentifizierung möglich ist -> Die Schnittmenge ist Null.
EDIT: Ähnlich, aber nicht ganz dasselbe: Du verbietest mit deiner Einschränkung der Chiffren ja alle gängigen Verfahren wie AES etc. Daher bleibt vermutlich kein gemeinsamer Nenner übrig. Versuche es doch mal ohne Begrenzung der Chiffren. Daß diese Authentifizierung ermöglichen muß ja nicht heißen, daß du diese auch nutzt.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

mkallas hat geschrieben:EDIT: Ähnlich, aber nicht ganz dasselbe: Du verbietest mit deiner Einschränkung der Chiffren ja alle gängigen Verfahren wie AES etc. Daher bleibt vermutlich kein gemeinsamer Nenner übrig. Versuche es doch mal ohne Begrenzung der Chiffren. Daß diese Authentifizierung ermöglichen muß ja nicht heißen, daß du diese auch nutzt.
Hi

In meinem Beispiel hab ich keine Begrenzung, habe auch schon von sock.get_cipher_list() ausgegeben und da kommt bei beiden (Server und Client) die selbe Liste heraus

Code: Alles auswählen

['DHE-RSA-AES256-SHA', 'DHE-DSS-AES256-SHA', 'AES256-SHA', 'EDH-RSA-DES-CBC3-SHA
', 'EDH-DSS-DES-CBC3-SHA', 'DES-CBC3-SHA', 'DHE-RSA-AES128-SHA', 'DHE-DSS-AES128
-SHA', 'AES128-SHA', 'IDEA-CBC-SHA', 'RC4-SHA', 'RC4-MD5', 'EDH-RSA-DES-CBC-SHA'
, 'EDH-DSS-DES-CBC-SHA', 'DES-CBC-SHA', 'EXP-EDH-RSA-DES-CBC-SHA', 'EXP-EDH-DSS-
DES-CBC-SHA', 'EXP-DES-CBC-SHA', 'EXP-RC2-CBC-MD5', 'EXP-RC4-MD5']
Also müsste es doch massig shared ciphers haben, hab auch schon probiert einzelne zu setzen aber immer mit dem gleichen Misserfolg.

Gruss
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

rayo hat geschrieben:ctx = SSL.Context(SSL.TLSv1_METHOD)
Hast Du auch mal SSL statt TLS versucht?
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Mit SSLv3 kommt der gleiche Fehler mit no shared ciphers.
Mit SSLv2 kommt folgendes:

Server:

Code: Alles auswählen

Waiting for connections.
Got connection from 127.0.0.1: 54044
Traceback (most recent call last):
  File "H:\Projects\_pySC\ssl\server.py", line 18, in <module>
    conn.recv(4096)
OpenSSL.SSL.Error: [('SSL routines', 'GET_CLIENT_MASTER_KEY', 'peer error certificate'),
 ('SSL routines', 'SSL2_READ_INTERNAL', 'ssl handshake failure')]
Client:

Code: Alles auswählen

Traceback (most recent call last):
  File "H:\Projects\_pySC\ssl\test.py", line 11, in <module>
    sock.write("Hallo")
OpenSSL.SSL.Error: [('asn1 encoding routines', 'ASN1_get_object', 'header too long'), 
('asn1 encoding routines', 'ASN1_CHECK_TLEN', 'bad object header'), 
('asn1 encoding routines', 'ASN1_ITEM_EX_D2I', 'nested asn1 error'), 
('SSL routines','SSL2_SET_CERTIFICATE', 'X509 lib')]
Damit kann ich leider nichts anfangen.

Gruss
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Klingt für mich so, als würde das Zertifikat nicht angenommen.
Der Client muß vermutlich auch einen Pfad zum Zertifikat haben.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Ich möchte aber kein Zertifikat, möchte nur eine verschlüsselte Verbindung, mehr nicht.

Gruss
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Antworten