mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	[3.13] gh-118658: Return consistent types from get_un/verified_chain in SSLObject and SSLSocket (GH-118669) (#123082)
				
					
				
			gh-118658: Return consistent types from `get_un/verified_chain` in `SSLObject` and `SSLSocket` (GH-118669)
(cherry picked from commit 8ef358dae1)
Co-authored-by: Mateusz Nowak <nowak.mateusz@hotmail.com>
Co-authored-by: Gregory P. Smith [Google LLC] <greg@krypto.org>
			
			
This commit is contained in:
		
							parent
							
								
									0a02026a08
								
							
						
					
					
						commit
						21399a0963
					
				
					 4 changed files with 86 additions and 2 deletions
				
			
		
							
								
								
									
										14
									
								
								Lib/ssl.py
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								Lib/ssl.py
									
										
									
									
									
								
							| 
						 | 
					@ -1165,11 +1165,21 @@ def getpeercert(self, binary_form=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @_sslcopydoc
 | 
					    @_sslcopydoc
 | 
				
			||||||
    def get_verified_chain(self):
 | 
					    def get_verified_chain(self):
 | 
				
			||||||
        return self._sslobj.get_verified_chain()
 | 
					        chain = self._sslobj.get_verified_chain()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if chain is None:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @_sslcopydoc
 | 
					    @_sslcopydoc
 | 
				
			||||||
    def get_unverified_chain(self):
 | 
					    def get_unverified_chain(self):
 | 
				
			||||||
        return self._sslobj.get_unverified_chain()
 | 
					        chain = self._sslobj.get_unverified_chain()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if chain is None:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [cert.public_bytes(_ssl.ENCODING_DER) for cert in chain]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @_sslcopydoc
 | 
					    @_sslcopydoc
 | 
				
			||||||
    def selected_npn_protocol(self):
 | 
					    def selected_npn_protocol(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								Lib/test/certdata/cert3.pem
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Lib/test/certdata/cert3.pem
									
										
									
										generated
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					-----BEGIN CERTIFICATE-----
 | 
				
			||||||
 | 
					MIIF8TCCBFmgAwIBAgIJAMstgJlaaVJcMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
 | 
				
			||||||
 | 
					BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
 | 
				
			||||||
 | 
					MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xODA4MjkxNDIzMTZaFw0zNzEwMjgx
 | 
				
			||||||
 | 
					NDIzMTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEj
 | 
				
			||||||
 | 
					MCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMMCWxv
 | 
				
			||||||
 | 
					Y2FsaG9zdDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKAqKHEL7aDt
 | 
				
			||||||
 | 
					3swl8hQF8VaK4zDGDRaF3E/IZTMwCN7FsQ4ejSiOe3E90f0phHCIpEpv2OebNenY
 | 
				
			||||||
 | 
					IpOGoFgkh62r/cthmnhu8Mn+FUIv17iOq7WX7B30OSqEpnr1voLX93XYkAq8LlMh
 | 
				
			||||||
 | 
					P79vsSCVhTwow3HZY7krEgl5WlfryOfj1i1TODSFPRCJePh66BsOTUvV/33GC+Qd
 | 
				
			||||||
 | 
					pVZVDGLowU1Ycmr/FdRvwT+F39Dehp03UFcxaX0/joPhH5gYpBB1kWTAQmxuqKMW
 | 
				
			||||||
 | 
					9ZZs6hrPtMXF/yfSrrXrzTdpct9paKR8RcufOcS8qju/ISK+1P/LXg2b5KJHedLo
 | 
				
			||||||
 | 
					TTIO3yCZ4d1odyuZBP7JDrI05gMJx95gz6sG685Qc+52MzLSTwr/Qg+MOjQoBy0o
 | 
				
			||||||
 | 
					8fRRVvIMEwoN0ZDb4uFEUuwZceUP1vTk/GGpNQt7ct4ropn6K4Zta3BUtovlLjZa
 | 
				
			||||||
 | 
					IIBhc1KETUqjRDvC6ACKmlcJ/5pY/dbH1lOux+IMFsh+djmaV90b3QIDAQABo4IB
 | 
				
			||||||
 | 
					wDCCAbwwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA4GA1UdDwEB/wQEAwIFoDAdBgNV
 | 
				
			||||||
 | 
					HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
 | 
				
			||||||
 | 
					FgQUP7HpT6C+MGY+ChjID0caTzRqD0IwfQYDVR0jBHYwdIAU8+yUjvKOMMSOaMK/
 | 
				
			||||||
 | 
					jmoZwMGfdmWhUaRPME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29m
 | 
				
			||||||
 | 
					dHdhcmUgRm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcoIJAMst
 | 
				
			||||||
 | 
					gJlaaVJbMIGDBggrBgEFBQcBAQR3MHUwPAYIKwYBBQUHMAKGMGh0dHA6Ly90ZXN0
 | 
				
			||||||
 | 
					Y2EucHl0aG9udGVzdC5uZXQvdGVzdGNhL3B5Y2FjZXJ0LmNlcjA1BggrBgEFBQcw
 | 
				
			||||||
 | 
					AYYpaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0Y2Evb2NzcC8wQwYD
 | 
				
			||||||
 | 
					VR0fBDwwOjA4oDagNIYyaHR0cDovL3Rlc3RjYS5weXRob250ZXN0Lm5ldC90ZXN0
 | 
				
			||||||
 | 
					Y2EvcmV2b2NhdGlvbi5jcmwwDQYJKoZIhvcNAQELBQADggGBAMo0usXQzycxMtYN
 | 
				
			||||||
 | 
					JzC42xfftzmnu7E7hsQx/fur22MazJCruU6rNEkMXow+cKOnay+nmiV7AVoYlkh2
 | 
				
			||||||
 | 
					+DZ4dPq8fWh/5cqmnXvccr2jJVEXaOjp1wKGLH0WfLXcRLIK4/fJM6NRNoO81HDN
 | 
				
			||||||
 | 
					hJGfBrot0gUKZcPZVQmouAlpu5OGwrfCkHR8v/BdvA5jE4zr+g/x+uUScE0M64wu
 | 
				
			||||||
 | 
					okJCAAQP/PkfQZxjePBmk7KPLuiTHFDLLX+2uldvUmLXOQsJgqumU03MBT4Z8NTA
 | 
				
			||||||
 | 
					zqmtEM65ceSP8lo8Zbrcy+AEkCulFaZ92tyjtbe8oN4wTmTLFw06oFLSZzuiOgDV
 | 
				
			||||||
 | 
					OaphdVKf/pvA6KBpr6izox0KQFIE5z3AAJZfKzMGDDD20xhy7jjQZNMAhjfsT+k4
 | 
				
			||||||
 | 
					SeYB/6KafNxq08uoulj7w4Z4R/EGpkXnU96ZHYHmvGN0RnxwI1cpYHCazG8AjsK/
 | 
				
			||||||
 | 
					anN9brBi5twTGrn+D8LRBqF5Yn+2MKkD0EdXJdtIENHP+32sPQ==
 | 
				
			||||||
 | 
					-----END CERTIFICATE-----
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,7 @@ def data_file(*name):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Two keys and certs signed by the same CA (for SNI tests)
 | 
					# Two keys and certs signed by the same CA (for SNI tests)
 | 
				
			||||||
SIGNED_CERTFILE = data_file("keycert3.pem")
 | 
					SIGNED_CERTFILE = data_file("keycert3.pem")
 | 
				
			||||||
 | 
					SINGED_CERTFILE_ONLY = data_file("cert3.pem")
 | 
				
			||||||
SIGNED_CERTFILE_HOSTNAME = 'localhost'
 | 
					SIGNED_CERTFILE_HOSTNAME = 'localhost'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SIGNED_CERTFILE_INFO = {
 | 
					SIGNED_CERTFILE_INFO = {
 | 
				
			||||||
| 
						 | 
					@ -4720,6 +4721,40 @@ def test_internal_chain_client(self):
 | 
				
			||||||
                    ssl.PEM_cert_to_DER_cert(pem), der
 | 
					                    ssl.PEM_cert_to_DER_cert(pem), der
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_certificate_chain(self):
 | 
				
			||||||
 | 
					        client_context, server_context, hostname = testing_context(
 | 
				
			||||||
 | 
					            server_chain=False
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        server = ThreadedEchoServer(context=server_context, chatty=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with open(SIGNING_CA) as f:
 | 
				
			||||||
 | 
					            expected_ca_cert = ssl.PEM_cert_to_DER_cert(f.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with open(SINGED_CERTFILE_ONLY) as f:
 | 
				
			||||||
 | 
					            expected_ee_cert = ssl.PEM_cert_to_DER_cert(f.read())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with server:
 | 
				
			||||||
 | 
					            with client_context.wrap_socket(
 | 
				
			||||||
 | 
					                socket.socket(),
 | 
				
			||||||
 | 
					                server_hostname=hostname
 | 
				
			||||||
 | 
					            ) as s:
 | 
				
			||||||
 | 
					                s.connect((HOST, server.port))
 | 
				
			||||||
 | 
					                vc = s.get_verified_chain()
 | 
				
			||||||
 | 
					                self.assertEqual(len(vc), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ee, ca = vc
 | 
				
			||||||
 | 
					                self.assertIsInstance(ee, bytes)
 | 
				
			||||||
 | 
					                self.assertIsInstance(ca, bytes)
 | 
				
			||||||
 | 
					                self.assertEqual(expected_ca_cert, ca)
 | 
				
			||||||
 | 
					                self.assertEqual(expected_ee_cert, ee)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                uvc = s.get_unverified_chain()
 | 
				
			||||||
 | 
					                self.assertEqual(len(uvc), 1)
 | 
				
			||||||
 | 
					                self.assertIsInstance(uvc[0], bytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.assertEqual(ee, uvc[0])
 | 
				
			||||||
 | 
					                self.assertNotEqual(ee, ca)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_internal_chain_server(self):
 | 
					    def test_internal_chain_server(self):
 | 
				
			||||||
        client_context, server_context, hostname = testing_context()
 | 
					        client_context, server_context, hostname = testing_context()
 | 
				
			||||||
        client_context.load_cert_chain(SIGNED_CERTFILE)
 | 
					        client_context.load_cert_chain(SIGNED_CERTFILE)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					You can now get the raw TLS certificate chains from TLS connections via
 | 
				
			||||||
 | 
					:meth:`ssl.SSLSocket.get_verified_chain` and
 | 
				
			||||||
 | 
					:meth:`ssl.SSLSocket.get_unverified_chain` methods.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Contributed by Mateusz Nowak.
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue