Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 72d2850

Browse files
committed
Issue #19292: Add SSLContext.load_default_certs() to load default root CA
certificates from default stores or system stores. By default the method loads CA certs for authentication of server certs.
1 parent a30d82f commit 72d2850

4 files changed

Lines changed: 94 additions & 1 deletion

File tree

Doc/library/ssl.rst

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,20 @@ Constants
681681

682682
.. versionadded:: 3.4
683683

684+
.. data:: Purpose.SERVER_AUTH
685+
686+
Option for :meth:`SSLContext.load_default_certs` to load CA certificates
687+
for TLS web server authentication (client side socket).
688+
689+
.. versionadded:: 3.4
690+
691+
.. data:: Purpose.clientAuth
692+
693+
Option for :meth:`SSLContext.load_default_certs` to load CA certificates
694+
for TLS web client authentication (server side socket).
695+
696+
.. versionadded:: 3.4
697+
684698

685699
SSL Sockets
686700
-----------
@@ -903,6 +917,22 @@ to speed up repeated connections from the same clients.
903917
.. versionchanged:: 3.3
904918
New optional argument *password*.
905919

920+
.. method:: SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)
921+
922+
Load a set of default "certification authority" (CA) certificates from
923+
default locations. On Windows it loads CA certs from the ``CA`` and
924+
``ROOT`` system stores. On other systems it calls
925+
:meth:`SSLContext.set_default_verify_paths`. In the future the method may
926+
load CA certificates from other locations, too.
927+
928+
The *purpose* flag specifies what kind of CA certificates are loaded. The
929+
default settings :data:`Purpose.SERVER_AUTH` loads certificates, that are
930+
flagged and trusted for TLS web server authentication (client side
931+
sockets). :data:`Purpose.clientAuth` loads CA certificates for client
932+
certificate verification on the server side.
933+
934+
.. versionadded:: 3.4
935+
906936
.. method:: SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)
907937

908938
Load a set of "certification authority" (CA) certificates used to validate
@@ -931,7 +961,6 @@ to speed up repeated connections from the same clients.
931961
.. versionchanged:: 3.4
932962
New optional argument *cadata*
933963

934-
935964
.. method:: SSLContext.get_ca_certs(binary_form=False)
936965

937966
Get a list of loaded "certification authority" (CA) certificates. If the

Lib/ssl.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
import sys
9393
import os
9494
from collections import namedtuple
95+
from enum import Enum as _Enum
9596

9697
import _ssl # if we can't import it, let the error propagate
9798

@@ -298,11 +299,19 @@ def fromname(cls, name):
298299
return super().__new__(cls, *_txt2obj(name, name=True))
299300

300301

302+
class Purpose(_ASN1Object, _Enum):
303+
"""SSLContext purpose flags with X509v3 Extended Key Usage objects
304+
"""
305+
SERVER_AUTH = '1.3.6.1.5.5.7.3.1'
306+
CLIENT_AUTH = '1.3.6.1.5.5.7.3.2'
307+
308+
301309
class SSLContext(_SSLContext):
302310
"""An SSLContext holds various SSL-related configuration options and
303311
data, such as certificates and possibly a private key."""
304312

305313
__slots__ = ('protocol', '__weakref__')
314+
_windows_cert_stores = ("CA", "ROOT")
306315

307316
def __new__(cls, protocol, *args, **kwargs):
308317
self = _SSLContext.__new__(cls, protocol)
@@ -334,6 +343,25 @@ def set_npn_protocols(self, npn_protocols):
334343

335344
self._set_npn_protocols(protos)
336345

346+
def _load_windows_store_certs(self, storename, purpose):
347+
certs = bytearray()
348+
for cert, encoding, trust in enum_certificates(storename):
349+
# CA certs are never PKCS#7 encoded
350+
if encoding == "x509_asn":
351+
if trust is True or purpose.oid in trust:
352+
certs.extend(cert)
353+
self.load_verify_locations(cadata=certs)
354+
return certs
355+
356+
def load_default_certs(self, purpose=Purpose.SERVER_AUTH):
357+
if not isinstance(purpose, _ASN1Object):
358+
raise TypeError(purpose)
359+
if sys.platform == "win32":
360+
for storename in self._windows_cert_stores:
361+
self._load_windows_store_certs(storename, purpose)
362+
else:
363+
self.set_default_verify_paths()
364+
337365

338366
class SSLSocket(socket):
339367
"""This class implements a subtype of socket.socket that wraps

Lib/test/test_ssl.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,23 @@ def test_asn1object(self):
611611
with self.assertRaisesRegex(ValueError, "unknown object 'serverauth'"):
612612
ssl._ASN1Object.fromname('serverauth')
613613

614+
def test_purpose_enum(self):
615+
val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
616+
self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
617+
self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
618+
self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
619+
self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
620+
self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
621+
'1.3.6.1.5.5.7.3.1')
622+
623+
val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
624+
self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
625+
self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
626+
self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
627+
self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
628+
self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
629+
'1.3.6.1.5.5.7.3.2')
630+
614631

615632
class ContextTests(unittest.TestCase):
616633

@@ -967,6 +984,21 @@ def test_get_ca_certs(self):
967984
der = ssl.PEM_cert_to_DER_cert(pem)
968985
self.assertEqual(ctx.get_ca_certs(True), [der])
969986

987+
def test_load_default_certs(self):
988+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
989+
ctx.load_default_certs()
990+
991+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
992+
ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
993+
ctx.load_default_certs()
994+
995+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
996+
ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
997+
998+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
999+
self.assertRaises(TypeError, ctx.load_default_certs, None)
1000+
self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
1001+
9701002

9711003
class SSLErrorTests(unittest.TestCase):
9721004

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ Core and Builtins
6868
Library
6969
-------
7070

71+
- Issue #19292: Add SSLContext.load_default_certs() to load default root CA
72+
certificates from default stores or system stores. By default the method
73+
loads CA certs for authentication of server certs.
74+
7175
- Issue #19673: Add pathlib to the stdlib as a provisional module (PEP 428).
7276

7377
- Issue #17916: Added dis.Bytecode.from_traceback() and

0 commit comments

Comments
 (0)