@@ -1023,6 +1023,24 @@ _decode_certificate(X509 *certificate) {
10231023 return NULL ;
10241024}
10251025
1026+ static PyObject *
1027+ _certificate_to_der (X509 * certificate )
1028+ {
1029+ unsigned char * bytes_buf = NULL ;
1030+ int len ;
1031+ PyObject * retval ;
1032+
1033+ bytes_buf = NULL ;
1034+ len = i2d_X509 (certificate , & bytes_buf );
1035+ if (len < 0 ) {
1036+ _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
1037+ return NULL ;
1038+ }
1039+ /* this is actually an immutable bytes sequence */
1040+ retval = PyBytes_FromStringAndSize ((const char * ) bytes_buf , len );
1041+ OPENSSL_free (bytes_buf );
1042+ return retval ;
1043+ }
10261044
10271045static PyObject *
10281046PySSL_test_decode_certificate (PyObject * mod , PyObject * args ) {
@@ -1068,8 +1086,6 @@ PySSL_test_decode_certificate (PyObject *mod, PyObject *args) {
10681086static PyObject *
10691087PySSL_peercert (PySSLSocket * self , PyObject * args )
10701088{
1071- PyObject * retval = NULL ;
1072- int len ;
10731089 int verification ;
10741090 int binary_mode = 0 ;
10751091
@@ -1081,21 +1097,7 @@ PySSL_peercert(PySSLSocket *self, PyObject *args)
10811097
10821098 if (binary_mode ) {
10831099 /* return cert in DER-encoded format */
1084-
1085- unsigned char * bytes_buf = NULL ;
1086-
1087- bytes_buf = NULL ;
1088- len = i2d_X509 (self -> peer_cert , & bytes_buf );
1089- if (len < 0 ) {
1090- PySSL_SetError (self , len , __FILE__ , __LINE__ );
1091- return NULL ;
1092- }
1093- /* this is actually an immutable bytes sequence */
1094- retval = PyBytes_FromStringAndSize
1095- ((const char * ) bytes_buf , len );
1096- OPENSSL_free (bytes_buf );
1097- return retval ;
1098-
1100+ return _certificate_to_der (self -> peer_cert );
10991101 } else {
11001102 verification = SSL_CTX_get_verify_mode (SSL_get_SSL_CTX (self -> ssl ));
11011103 if ((verification & SSL_VERIFY_PEER ) == 0 )
@@ -2555,6 +2557,110 @@ set_servername_callback(PySSLContext *self, PyObject *args)
25552557#endif
25562558}
25572559
2560+ PyDoc_STRVAR (PySSL_get_stats_doc ,
2561+ "cert_store_stats() -> {'crl': int, 'x509_ca': int, 'x509': int}\n\
2562+ \n\
2563+ Returns quantities of loaded X.509 certificates. X.509 certificates with a\n\
2564+ CA extension and certificate revocation lists inside the context's cert\n\
2565+ store.\n\
2566+ NOTE: Certificates in a capath directory aren't loaded unless they have\n\
2567+ been used at least once." );
2568+
2569+ static PyObject *
2570+ cert_store_stats (PySSLContext * self )
2571+ {
2572+ X509_STORE * store ;
2573+ X509_OBJECT * obj ;
2574+ int x509 = 0 , crl = 0 , pkey = 0 , ca = 0 , i ;
2575+
2576+ store = SSL_CTX_get_cert_store (self -> ctx );
2577+ for (i = 0 ; i < sk_X509_OBJECT_num (store -> objs ); i ++ ) {
2578+ obj = sk_X509_OBJECT_value (store -> objs , i );
2579+ switch (obj -> type ) {
2580+ case X509_LU_X509 :
2581+ x509 ++ ;
2582+ if (X509_check_ca (obj -> data .x509 )) {
2583+ ca ++ ;
2584+ }
2585+ break ;
2586+ case X509_LU_CRL :
2587+ crl ++ ;
2588+ break ;
2589+ case X509_LU_PKEY :
2590+ pkey ++ ;
2591+ break ;
2592+ default :
2593+ /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
2594+ * As far as I can tell they are internal states and never
2595+ * stored in a cert store */
2596+ break ;
2597+ }
2598+ }
2599+ return Py_BuildValue ("{sisisi}" , "x509" , x509 , "crl" , crl ,
2600+ "x509_ca" , ca );
2601+ }
2602+
2603+ PyDoc_STRVAR (PySSL_get_ca_certs_doc ,
2604+ "get_ca_certs([der=False]) -> list of loaded certificate\n\
2605+ \n\
2606+ Returns a list of dicts with information of loaded CA certs. If the\n\
2607+ optional argument is True, returns a DER-encoded copy of the CA certificate.\n\
2608+ NOTE: Certificates in a capath directory aren't loaded unless they have\n\
2609+ been used at least once." );
2610+
2611+ static PyObject *
2612+ get_ca_certs (PySSLContext * self , PyObject * args )
2613+ {
2614+ X509_STORE * store ;
2615+ PyObject * ci = NULL , * rlist = NULL ;
2616+ int i ;
2617+ int binary_mode = 0 ;
2618+
2619+ if (!PyArg_ParseTuple (args , "|p:get_ca_certs" , & binary_mode )) {
2620+ return NULL ;
2621+ }
2622+
2623+ if ((rlist = PyList_New (0 )) == NULL ) {
2624+ return NULL ;
2625+ }
2626+
2627+ store = SSL_CTX_get_cert_store (self -> ctx );
2628+ for (i = 0 ; i < sk_X509_OBJECT_num (store -> objs ); i ++ ) {
2629+ X509_OBJECT * obj ;
2630+ X509 * cert ;
2631+
2632+ obj = sk_X509_OBJECT_value (store -> objs , i );
2633+ if (obj -> type != X509_LU_X509 ) {
2634+ /* not a x509 cert */
2635+ continue ;
2636+ }
2637+ /* CA for any purpose */
2638+ cert = obj -> data .x509 ;
2639+ if (!X509_check_ca (cert )) {
2640+ continue ;
2641+ }
2642+ if (binary_mode ) {
2643+ ci = _certificate_to_der (cert );
2644+ } else {
2645+ ci = _decode_certificate (cert );
2646+ }
2647+ if (ci == NULL ) {
2648+ goto error ;
2649+ }
2650+ if (PyList_Append (rlist , ci ) == -1 ) {
2651+ goto error ;
2652+ }
2653+ Py_CLEAR (ci );
2654+ }
2655+ return rlist ;
2656+
2657+ error :
2658+ Py_XDECREF (ci );
2659+ Py_XDECREF (rlist );
2660+ return NULL ;
2661+ }
2662+
2663+
25582664static PyGetSetDef context_getsetlist [] = {
25592665 {"options" , (getter ) get_options ,
25602666 (setter ) set_options , NULL },
@@ -2586,6 +2692,10 @@ static struct PyMethodDef context_methods[] = {
25862692#endif
25872693 {"set_servername_callback" , (PyCFunction ) set_servername_callback ,
25882694 METH_VARARGS , PySSL_set_servername_callback_doc },
2695+ {"cert_store_stats" , (PyCFunction ) cert_store_stats ,
2696+ METH_NOARGS , PySSL_get_stats_doc },
2697+ {"get_ca_certs" , (PyCFunction ) get_ca_certs ,
2698+ METH_VARARGS , PySSL_get_ca_certs_doc },
25892699 {NULL , NULL } /* sentinel */
25902700};
25912701
0 commit comments