@@ -2082,6 +2082,133 @@ _ssl__SSLSocket_cipher_impl(PySSLSocket *self)
20822082 return cipher_to_tuple (current );
20832083}
20842084
2085+ /*[clinic input]
2086+ _ssl._SSLSocket.getpeercertchain
2087+ der as binary_mode: bool = False
2088+ validate: bool = True
2089+ [clinic start generated code]*/
2090+
2091+ static PyObject *
2092+ _ssl__SSLSocket_getpeercertchain_impl (PySSLSocket * self , int binary_mode ,
2093+ int validate )
2094+ /*[clinic end generated code: output=8094e6d78d27eb9a input=f4dcd181d0d163eb]*/
2095+ {
2096+ int len , i ;
2097+ PyObject * retval = NULL , * ci = NULL ;
2098+ STACK_OF (X509 ) * peer_chain ; /* reference */
2099+
2100+ assert ((self -> ctx != NULL ) && (self -> ctx -> ctx != NULL ));
2101+ if (self -> ssl == NULL ) {
2102+ Py_RETURN_NONE ;
2103+ }
2104+
2105+ /* The peer just transmits the intermediate cert chain EXCLUDING the root
2106+ * CA certificate as this side is suppose to have a copy of the root
2107+ * certificate for verification. */
2108+ if (validate ) {
2109+ #ifdef OPENSSL_VERSION_1_1
2110+ peer_chain = SSL_get0_verified_chain (self -> ssl );
2111+ long ret = SSL_get_verify_result (self -> ssl );
2112+ if (ret != X509_V_OK ) {
2113+ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED
2114+ long e = ERR_PACK (ERR_LIB_SSL , 0 , SSL_R_CERTIFICATE_VERIFY_FAILED );
2115+ #else
2116+ long e = ERR_PACK (ERR_LIB_SSL , 0 , 134 );
2117+ #endif
2118+ fill_and_set_sslerror (self , PySSLCertVerificationErrorObject , PY_SSL_ERROR_SSL , NULL , __LINE__ , e );
2119+ return NULL ;
2120+ }
2121+ #else
2122+ X509 * peer_cert = SSL_get_peer_certificate (self -> ssl );
2123+ if (peer_cert == NULL )
2124+ Py_RETURN_NONE ;
2125+
2126+ STACK_OF (X509 ) * chain = SSL_get_peer_cert_chain (self -> ssl );
2127+ if (chain == NULL ) {
2128+ X509_free (peer_cert );
2129+ Py_RETURN_NONE ;
2130+ }
2131+ X509_STORE_CTX * store_ctx ;
2132+
2133+ /* Initialize a store context with store (for root CA certs), the
2134+ * peer's cert and the peer's chain with intermediate CA certs. */
2135+ if ((store_ctx = X509_STORE_CTX_new ()) == NULL ) {
2136+ X509_free (peer_cert );
2137+ _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
2138+ return NULL ;
2139+ }
2140+
2141+ if (!X509_STORE_CTX_init (store_ctx ,
2142+ SSL_CTX_get_cert_store (self -> ctx -> ctx ),
2143+ peer_cert , chain )) {
2144+ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED
2145+ long e = ERR_PACK (ERR_LIB_SSL , 0 , SSL_R_CERTIFICATE_VERIFY_FAILED );
2146+ #else
2147+ long e = ERR_PACK (ERR_LIB_SSL , 0 , 134 );
2148+ #endif
2149+ fill_and_set_sslerror (self , PySSLCertVerificationErrorObject , PY_SSL_ERROR_SSL , NULL , __LINE__ , e );
2150+ X509_free (peer_cert );
2151+ X509_STORE_CTX_free (store_ctx );
2152+ goto end ;
2153+ }
2154+ X509_free (peer_cert );
2155+
2156+ /* Validate peer cert using its intermediate CA certs and the
2157+ * context's root CA certs. */
2158+ if (X509_verify_cert (store_ctx ) <= 0 ) {
2159+ // _setX509StoreContextError(self, store_ctx, __FILE__, __LINE__);
2160+ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED
2161+ long e = ERR_PACK (ERR_LIB_SSL , 0 , SSL_R_CERTIFICATE_VERIFY_FAILED );
2162+ #else
2163+ long e = ERR_PACK (ERR_LIB_SSL , 0 , 134 );
2164+ #endif
2165+ fill_and_set_sslerror (self , PySSLCertVerificationErrorObject , PY_SSL_ERROR_SSL , NULL , __LINE__ , e );
2166+ X509_STORE_CTX_free (store_ctx );
2167+ goto end ;
2168+ }
2169+
2170+ /* Get chain from store context */
2171+ peer_chain = X509_STORE_CTX_get1_chain (store_ctx );
2172+ X509_STORE_CTX_free (store_ctx );
2173+ #endif
2174+ } else {
2175+ peer_chain = SSL_get_peer_cert_chain (self -> ssl );
2176+ }
2177+
2178+ if (peer_chain == NULL ) {
2179+ Py_RETURN_NONE ;
2180+ }
2181+
2182+ len = sk_X509_num (peer_chain );
2183+
2184+ if ((retval = PyTuple_New (len )) == NULL ) {
2185+ return NULL ;
2186+ }
2187+
2188+ for (i = 0 ; i < len ; i ++ ){
2189+ X509 * cert = sk_X509_value (peer_chain , i );
2190+ if (binary_mode ) {
2191+ ci = _certificate_to_der (cert );
2192+ } else {
2193+ ci = _decode_certificate (cert );
2194+ }
2195+
2196+ if (ci == NULL ) {
2197+ Py_CLEAR (retval );
2198+ goto end ;
2199+ }
2200+ PyTuple_SET_ITEM (retval , i , ci );
2201+ }
2202+
2203+ end :
2204+ #ifndef OPENSSL_VERSION_1_1
2205+ if (validate && (peer_chain != NULL )) {
2206+ sk_X509_pop_free (peer_chain , X509_free );
2207+ }
2208+ #endif
2209+ return retval ;
2210+ }
2211+
20852212/*[clinic input]
20862213_ssl._SSLSocket.version
20872214[clinic start generated code]*/
@@ -2984,6 +3111,7 @@ static PyMethodDef PySSLMethods[] = {
29843111 _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF
29853112 _SSL__SSLSOCKET_CIPHER_METHODDEF
29863113 _SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF
3114+ _SSL__SSLSOCKET_GETPEERCERTCHAIN_METHODDEF
29873115 _SSL__SSLSOCKET_VERSION_METHODDEF
29883116 _SSL__SSLSOCKET_SELECTED_NPN_PROTOCOL_METHODDEF
29893117 _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
0 commit comments