ssl — SSL/TLS modülü

Bu modül, hem istemci hem de sunucu tarafında ağ soketleri için Transport Layer Security (önceden ve yaygın olarak “Secure Sockets Layer” olarak bilinen) şifreleme ve karşı taraf kimlik doğrulama olanaklarına erişim sağlar.

Tüyo

Kamerada TLS konusunda yeni misiniz? TLS sertifikalarıyla çalışma öğreticisiyle başlayın. Bu öğretici; anahtar türlerini seçmeyi, sertifikaları oluşturmayı ve kameranın gerektirdiği DER biçimine dönüştürmeyi, bunları cihaza aktarmayı ve sunucularla istemcileri doğrulamayı tam çalışan örneklerle adım adım anlatır.

Not

MicroPython ssl.SSLError öğesini uygulamaz. SSL/TLS hataları bunun yerine OSError olarak yükseltilir.

Örnekler

Sunucunun sertifikasını, dosya sisteminde saklanan (DER biçimindeki) bir CA sertifikasıyla doğrulayan TLS istemcisi:

import socket
import ssl
import ntptime

# CERT_REQUIRED checks the certificate's validity dates, so the clock
# must be set (see the certificates tutorial linked above).
ntptime.settime()

# Open a plain TCP connection.
addr = socket.getaddrinfo("example.com", 443)[0][-1]
sock = socket.socket()
sock.connect(addr)

# Wrap it for TLS and require a valid certificate.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="ca.der")
ssock = ctx.wrap_socket(sock, server_hostname="example.com")

ssock.write(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
print(ssock.read())
ssock.close()

Hızlı ve güvensiz bir bağlantı için (sertifika doğrulaması olmadan) bunun yerine ssl.wrap_socket() kolaylık işlevi kullanılabilir:

ssock = ssl.wrap_socket(sock, server_hostname="example.com")

Kendi sertifikasını ve özel anahtarını (DER biçimi) sunan TLS sunucusu:

import socket
import ssl

sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(socket.getaddrinfo("0.0.0.0", 8443)[0][-1])
sock.listen(1)

ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("server.der", "server.key")

while True:
    client, addr = sock.accept()
    sclient = ctx.wrap_socket(client, server_side=True)
    sclient.write(b"hello\n")
    sclient.close()

İşlevler

ssl.wrap_socket(sock: Any, server_side: bool = False, key: bytes | None = None, cert: bytes | None = None, cert_reqs: int = CERT_NONE, cadata: bytes | None = None, server_hostname: str | None = None, do_handshake: bool = True) Any

Verilen sock öğesini sarmalar ve yeni bir sarmalanmış soket nesnesi döndürür. Bu işlevin uygulanışı, önce bir SSLContext oluşturmak ve ardından o bağlam nesnesi üzerinde SSLContext.wrap_socket() yöntemini çağırmaktır. sock, server_side ve server_hostname argümanları yöntem çağrısına değiştirilmeden aktarılır. do_handshake argümanı do_handshake_on_connect olarak aktarılır. Kalan argümanlar şu davranışa sahiptir:

  • cert_reqs, karşı tarafın (sunucu veya istemci) geçerli bir sertifika sunması gerekip gerekmediğini belirler. ssl.CERT_NONE ve ssl.CERT_OPTIONAL öğelerinin hiçbir sertifikayı doğrulamadığını; yalnızca ssl.CERT_REQUIRED öğesinin doğruladığını unutmayın.

  • cadata, karşı tarafın sertifikasını doğrulayacak CA sertifika zincirini (DER biçiminde) içeren bir bytes nesnesidir. Şu anda yalnızca tek bir DER kodlu sertifika desteklenmektedir.

Sınıflar

class ssl.SSLContext(protocol: int, /)

Yeni bir SSLContext örneği oluşturur. protocol argümanı PROTOCOL_* sabitlerinden biri olmalıdır.

load_cert_chain(certfile: str | bytes, keyfile: str | bytes) None

Bir özel anahtarı ve ona karşılık gelen sertifikayı yükler. certfile, sertifikanın dosya yolunu içeren bir dizgedir. keyfile, özel anahtarın dosya yolunu içeren bir dizgedir.

CPython’dan Farkı

MicroPython eklentisi: certfile ve keyfile, dizge yerine bytes nesneleri olabilir; bu durumda gerçek sertifika/anahtar verisi olarak yorumlanırlar.

load_verify_locations(cafile: str | None = None, cadata: bytes | None = None) None

Karşı tarafın sertifikasını doğrulayacak CA sertifika zincirini yükler. cafile, CA sertifikalarının dosya yoludur. cadata, CA sertifikalarını içeren bir bytes nesnesidir. Bu argümanlardan yalnızca biri sağlanmalıdır.

get_ciphers() List[str]

Etkin şifrelerin bir listesini, dizgelerden oluşan bir liste olarak döndürür.

set_ciphers(ciphers: List[str]) None

Bu bağlamla oluşturulan soketler için kullanılabilir şifreleri ayarlar. ciphers, IANA cipher suite biçiminde dizgelerden oluşan bir liste olmalıdır.

wrap_socket(sock: Any, *, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname: str | None = None, client_id: bytes | None = None) Any

Bir stream sock (genellikle SOCK_STREAM türünde bir socket.socket örneği) alır ve alttaki akışı sarmalayan bir ssl.SSLSocket örneği döndürür. Döndürülen nesne, read(), write() gibi olağan stream arayüz yöntemlerine sahiptir.

  • server_side, sarmalanan soketin sunucu tarafında mı yoksa istemci tarafında mı olduğunu seçer. Sunucu tarafı bir SSL soketi, SSL olmayan bir dinleyici sunucu soketi üzerinde accept() çağrısından döndürülen normal bir soketten oluşturulmalıdır.

  • do_handshake_on_connect, el sıkışmanın wrap_socket işleminin bir parçası olarak mı yapılacağını yoksa ilk okuma veya yazmaların bir parçası olarak yapılmak üzere ertelenip ertelenmeyeceğini belirler. Bloklayan soketler için el sıkışmayı hemen yapmak standarttır. Bloklamayan soketler için (yani wrap_socket öğesine aktarılan sock bloklamayan moddayken) el sıkışma genellikle ertelenmelidir, çünkü aksi takdirde wrap_socket tamamlanana kadar bloklar.

  • server_hostname, istemci olarak kullanım içindir ve alınan sunucu sertifikasına karşı denetlenecek ana makine adını ayarlar. Ayrıca Server Name Indication (SNI) için adı belirler ve sunucunun uygun sertifikayı sunmasına olanak tanır.

  • client_id, yalnızca bir DTLS Sunucusu uygulanırken kullanılan, MicroPython’a özgü bir eklenti argümanıdır. Ayrıntılar için bkz. DTLS desteği.

Uyarı

Varsayılan olarak hiçbir sertifika doğrulaması yapılmaz (ssl.CERT_NONE). Güvenli bir bağlantı için cert_reqs / SSLContext.verify_mode öğesini ssl.CERT_REQUIRED olarak ayarlayarak karşı tarafın sertifikasını doğrulamanız gerekir; aksi takdirde bağlantı ortadaki adam (man-in-the-middle) saldırılarına karşı savunmasızdır.

CPython’un wrap_socket işlevi, send, recv gibi soketlere özgü yöntemlere sahip bir SSLSocket nesnesi döndürür. MicroPython’un wrap_socket işlevi ise CPython’un SSLObject öğesine daha benzer, bu soket yöntemlerine sahip olmayan bir nesne döndürür.

verify_mode

Karşı taraf sertifikalarının doğrulanma davranışını ayarlar veya alır. CERT_* sabitlerinden biri olmalıdır.

Not

ssl.CERT_REQUIRED, cihazın tarih/saatinin doğru ayarlanmış olmasını gerektirir; örneğin mpremote rtc --set veya ntptime kullanılarak. Ayrıca istemci tarafındayken server_hostname belirtilmelidir.

DTLS desteği

CPython’dan Farkı

Bu bir MicroPython eklentisidir.

Bu modül, SSLContext öğesinin protocol argümanı olarak kullanılabilen PROTOCOL_DTLS_CLIENT ve PROTOCOL_DTLS_SERVER sabitleri aracılığıyla istemci ve sunucu modunda DTLS’yi destekler.

Bu durumda alttaki soketin bir datagram soketi gibi davranması beklenir (yani af olarak socket.AF_INET ve type olarak socket.SOCK_DGRAM ile socket.socket kullanılarak açılan soket gibi).

DTLS sunucu desteği

MicroPython’un DTLS sunucu desteği, DTLS 1.2 için gerektiği gibi “Hello Verify” ile yapılandırılmıştır. Bu, DTLS istemcileri için saydamdır, ancak MicroPython’da bir DTLS sunucusu uygularken ilgili noktalar vardır:

  • Sunucu, SSLContext.wrap_socket() çağırırken ek bir client_id argümanı geçmelidir. Bu kimlik, istemciyi temsil eden taşımaya özgü bir tanımlayıcı içeren bir bytes nesnesi (veya benzeri) olmalıdır.

    En basit yaklaşım, socket.recv_from() öğesinden döndürülen (client_ip, client_port) demetini bir bayt dizgesine dönüştürmektir; yani:

    _, client_addr = sock.recvfrom(1, socket.MSG_PEEK)
    sock.connect(client_addr)  # Connect back to the client
    sock = ssl_ctx.wrap_socket(sock, server_side=True,
                               client_id=repr(client_addr).encode())
    
  • Bir istemci ilk kez bağlandığında, sunucunun wrap_socket çağrısı “Hello Verify Required” hatasıyla bir OSError hatası vererek başarısız olur. Bunun nedeni, DTLS “Hello Verify” çerezinin istemci tarafından henüz bilinmemesidir. Aynı istemci ikinci kez bağlanırsa wrap_socket başarılı olur.

  • “Hello Verify” için DTLS çerezleri SSLContext nesnesiyle ilişkilendirilir, bu nedenle aynı istemciden gelen sonraki bir bağlantıyı sarmalamak için aynı SSLContext nesnesi kullanılmalıdır. Çerez uygulaması bir zaman aşımı içerir ve kaç istemcinin bağlandığından bağımsız olarak sabit bellek kullanımına sahiptir, dolayısıyla aynı SSLContext nesnesini sunucunun ömrü boyunca yeniden kullanmak sorun değildir.

Sabitler

ssl.PROTOCOL_TLS_CLIENT: int

TLS istemci modunu seçen, protocol parametresi için desteklenen değer.

ssl.PROTOCOL_TLS_SERVER: int

TLS sunucu modunu seçen, protocol parametresi için desteklenen değer.

ssl.PROTOCOL_DTLS_CLIENT: int

DTLS istemci modunu seçen, protocol parametresi için desteklenen değer.

ssl.PROTOCOL_DTLS_SERVER: int

DTLS sunucu modunu seçen, protocol parametresi için desteklenen değer.

ssl.CERT_NONE: int

cert_reqs parametresi ve SSLContext.verify_mode özniteliği için desteklenen değer. Karşı tarafta hiçbir sertifika doğrulaması yapılmaz.

ssl.CERT_OPTIONAL: int

cert_reqs parametresi ve SSLContext.verify_mode özniteliği için desteklenen değer. Sertifika doğrulaması isteğe bağlıdır. OpenMV Cam üzerinde bunun ssl.CERT_NONE gibi davrandığını unutmayın.

ssl.CERT_REQUIRED: int

cert_reqs parametresi ve SSLContext.verify_mode özniteliği için desteklenen değer. Karşı taraftan geçerli bir sertifika gereklidir.