@@ -513,6 +513,8 @@ fill_and_set_sslerror(_sslmodulestate *state,
513513 PyObject * verify_obj = NULL , * verify_code_obj = NULL ;
514514 PyObject * init_value , * msg , * key ;
515515 PyUnicodeWriter * writer = NULL ;
516+ PyObject * error_queue = PyList_New (0 );
517+ if (!error_queue ) goto fail ;
516518
517519 if (ssl_errno == PY_SSL_ERROR_EOF && sslsock != NULL ) {
518520 sslsock -> got_eof_error = 1 ;
@@ -542,6 +544,45 @@ fill_and_set_sslerror(_sslmodulestate *state,
542544 if (errstr == NULL ) {
543545 errstr = ERR_reason_error_string (errcode );
544546 }
547+
548+ /* populate error_list from OpenSSL's error queue */
549+ unsigned int q_pos = 0 ; /* Error queue position */
550+ const char * eq_filename , * eq_func , * eq_data ;
551+ char eq_msg [256 ];
552+ int eq_lineno ;
553+ int flags ; /* Flags (discarded) */
554+ unsigned long openssl_errorcode ;
555+
556+ /* Presumably, we no longer need the OpenSSL error queue after this, so
557+ we can call ERR_get_error (destructive) instead of ERR_peek_error */
558+ while ((openssl_errorcode = ERR_get_error_all (& eq_filename , & eq_lineno , & eq_func ,
559+ & eq_data , & flags ))) {
560+ if (q_pos == 0 ) {
561+ /* errcode should have come from a caller, and should have been
562+ returned from ERR_peek_last_error() */
563+ assert (openssl_errorcode == errcode );
564+ }
565+
566+ ERR_error_string_n (openssl_errorcode , eq_msg , 256 );
567+
568+ // Follows [lib reason] error_string extra_data (OpenSSL file:func:line)
569+ PyObject * current_eq_msg = NULL ;
570+ if (eq_data != NULL ) {
571+ current_eq_msg = PyUnicode_FromFormat (
572+ "%s %s (%s:%s:%d)" ,
573+ eq_msg , eq_data , eq_filename , eq_func , eq_lineno
574+ );
575+ } else {
576+ current_eq_msg = PyUnicode_FromFormat (
577+ "%s (%s:%s:%d)" ,
578+ eq_msg , eq_filename , eq_func , eq_lineno
579+ );
580+ }
581+ if (PyList_Append (error_queue , current_eq_msg ) != 0 ) {
582+ goto fail ;
583+ }
584+ q_pos ++ ;
585+ }
545586 }
546587
547588 /* verify code for cert validation error */
@@ -655,6 +696,12 @@ fill_and_set_sslerror(_sslmodulestate *state,
655696 goto fail ;
656697 }
657698
699+ /* Add the full OpenSSL error queue to exception */
700+ if (PyObject_SetAttr (err_value , state -> str_error_queue , error_queue ) != 0 ) {
701+ goto fail ;
702+ }
703+ Py_DECREF (error_queue );
704+
658705 PyErr_SetObject (type , err_value );
659706fail :
660707 Py_XDECREF (err_value );
@@ -7359,6 +7406,10 @@ sslmodule_init_strings(PyObject *module)
73597406 if (state -> str_verify_code == NULL ) {
73607407 return -1 ;
73617408 }
7409+ state -> str_error_queue = PyUnicode_InternFromString ("error_queue" );
7410+ if (state -> str_error_queue == NULL ) {
7411+ return -1 ;
7412+ }
73627413 return 0 ;
73637414}
73647415
0 commit comments