@@ -2304,60 +2304,200 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
23042304 return NULL ;
23052305}
23062306
2307+ /* internal helper function, returns -1 on error
2308+ */
2309+ static int
2310+ _add_ca_certs (PySSLContext * self , void * data , Py_ssize_t len ,
2311+ int filetype )
2312+ {
2313+ BIO * biobuf = NULL ;
2314+ X509_STORE * store ;
2315+ int retval = 0 , err , loaded = 0 ;
2316+
2317+ assert (filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM );
2318+
2319+ if (len <= 0 ) {
2320+ PyErr_SetString (PyExc_ValueError ,
2321+ "Empty certificate data" );
2322+ return -1 ;
2323+ } else if (len > INT_MAX ) {
2324+ PyErr_SetString (PyExc_OverflowError ,
2325+ "Certificate data is too long." );
2326+ return -1 ;
2327+ }
2328+
2329+ biobuf = BIO_new_mem_buf (data , len );
2330+ if (biobuf == NULL ) {
2331+ _setSSLError ("Can't allocate buffer" , 0 , __FILE__ , __LINE__ );
2332+ return -1 ;
2333+ }
2334+
2335+ store = SSL_CTX_get_cert_store (self -> ctx );
2336+ assert (store != NULL );
2337+
2338+ while (1 ) {
2339+ X509 * cert = NULL ;
2340+ int r ;
2341+
2342+ if (filetype == SSL_FILETYPE_ASN1 ) {
2343+ cert = d2i_X509_bio (biobuf , NULL );
2344+ } else {
2345+ cert = PEM_read_bio_X509 (biobuf , NULL ,
2346+ self -> ctx -> default_passwd_callback ,
2347+ self -> ctx -> default_passwd_callback_userdata );
2348+ }
2349+ if (cert == NULL ) {
2350+ break ;
2351+ }
2352+ r = X509_STORE_add_cert (store , cert );
2353+ X509_free (cert );
2354+ if (!r ) {
2355+ err = ERR_peek_last_error ();
2356+ if ((ERR_GET_LIB (err ) == ERR_LIB_X509 ) &&
2357+ (ERR_GET_REASON (err ) == X509_R_CERT_ALREADY_IN_HASH_TABLE )) {
2358+ /* cert already in hash table, not an error */
2359+ ERR_clear_error ();
2360+ } else {
2361+ break ;
2362+ }
2363+ }
2364+ loaded ++ ;
2365+ }
2366+
2367+ err = ERR_peek_last_error ();
2368+ if ((filetype == SSL_FILETYPE_ASN1 ) &&
2369+ (loaded > 0 ) &&
2370+ (ERR_GET_LIB (err ) == ERR_LIB_ASN1 ) &&
2371+ (ERR_GET_REASON (err ) == ASN1_R_HEADER_TOO_LONG )) {
2372+ /* EOF ASN1 file, not an error */
2373+ ERR_clear_error ();
2374+ retval = 0 ;
2375+ } else if ((filetype == SSL_FILETYPE_PEM ) &&
2376+ (loaded > 0 ) &&
2377+ (ERR_GET_LIB (err ) == ERR_LIB_PEM ) &&
2378+ (ERR_GET_REASON (err ) == PEM_R_NO_START_LINE )) {
2379+ /* EOF PEM file, not an error */
2380+ ERR_clear_error ();
2381+ retval = 0 ;
2382+ } else {
2383+ _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
2384+ retval = -1 ;
2385+ }
2386+
2387+ BIO_free (biobuf );
2388+ return retval ;
2389+ }
2390+
2391+
23072392static PyObject *
23082393load_verify_locations (PySSLContext * self , PyObject * args , PyObject * kwds )
23092394{
2310- char * kwlist [] = {"cafile" , "capath" , NULL };
2311- PyObject * cafile = NULL , * capath = NULL ;
2395+ char * kwlist [] = {"cafile" , "capath" , "cadata" , NULL };
2396+ PyObject * cafile = NULL , * capath = NULL , * cadata = NULL ;
23122397 PyObject * cafile_bytes = NULL , * capath_bytes = NULL ;
23132398 const char * cafile_buf = NULL , * capath_buf = NULL ;
2314- int r ;
2399+ int r = 0 , ok = 1 ;
23152400
23162401 errno = 0 ;
23172402 if (!PyArg_ParseTupleAndKeywords (args , kwds ,
2318- "|OO :load_verify_locations" , kwlist ,
2319- & cafile , & capath ))
2403+ "|OOO :load_verify_locations" , kwlist ,
2404+ & cafile , & capath , & cadata ))
23202405 return NULL ;
2406+
23212407 if (cafile == Py_None )
23222408 cafile = NULL ;
23232409 if (capath == Py_None )
23242410 capath = NULL ;
2325- if (cafile == NULL && capath == NULL ) {
2411+ if (cadata == Py_None )
2412+ cadata = NULL ;
2413+
2414+ if (cafile == NULL && capath == NULL && cadata == NULL ) {
23262415 PyErr_SetString (PyExc_TypeError ,
2327- "cafile and capath cannot be both omitted" );
2328- return NULL ;
2416+ "cafile, capath and cadata cannot be all omitted" );
2417+ goto error ;
23292418 }
23302419 if (cafile && !PyUnicode_FSConverter (cafile , & cafile_bytes )) {
23312420 PyErr_SetString (PyExc_TypeError ,
23322421 "cafile should be a valid filesystem path" );
2333- return NULL ;
2422+ goto error ;
23342423 }
23352424 if (capath && !PyUnicode_FSConverter (capath , & capath_bytes )) {
2336- Py_XDECREF (cafile_bytes );
23372425 PyErr_SetString (PyExc_TypeError ,
23382426 "capath should be a valid filesystem path" );
2339- return NULL ;
2427+ goto error ;
23402428 }
2341- if (cafile )
2342- cafile_buf = PyBytes_AS_STRING (cafile_bytes );
2343- if (capath )
2344- capath_buf = PyBytes_AS_STRING (capath_bytes );
2345- PySSL_BEGIN_ALLOW_THREADS
2346- r = SSL_CTX_load_verify_locations (self -> ctx , cafile_buf , capath_buf );
2347- PySSL_END_ALLOW_THREADS
2348- Py_XDECREF (cafile_bytes );
2349- Py_XDECREF (capath_bytes );
2350- if (r != 1 ) {
2351- if (errno != 0 ) {
2352- ERR_clear_error ();
2353- PyErr_SetFromErrno (PyExc_IOError );
2429+
2430+ /* validata cadata type and load cadata */
2431+ if (cadata ) {
2432+ Py_buffer buf ;
2433+ PyObject * cadata_ascii = NULL ;
2434+
2435+ if (PyObject_GetBuffer (cadata , & buf , PyBUF_SIMPLE ) == 0 ) {
2436+ if (!PyBuffer_IsContiguous (& buf , 'C' ) || buf .ndim > 1 ) {
2437+ PyBuffer_Release (& buf );
2438+ PyErr_SetString (PyExc_TypeError ,
2439+ "cadata should be a contiguous buffer with "
2440+ "a single dimension" );
2441+ goto error ;
2442+ }
2443+ r = _add_ca_certs (self , buf .buf , buf .len , SSL_FILETYPE_ASN1 );
2444+ PyBuffer_Release (& buf );
2445+ if (r == -1 ) {
2446+ goto error ;
2447+ }
2448+ } else {
2449+ PyErr_Clear ();
2450+ cadata_ascii = PyUnicode_AsASCIIString (cadata );
2451+ if (cadata_ascii == NULL ) {
2452+ PyErr_SetString (PyExc_TypeError ,
2453+ "cadata should be a ASCII string or a "
2454+ "bytes-like object" );
2455+ goto error ;
2456+ }
2457+ r = _add_ca_certs (self ,
2458+ PyBytes_AS_STRING (cadata_ascii ),
2459+ PyBytes_GET_SIZE (cadata_ascii ),
2460+ SSL_FILETYPE_PEM );
2461+ Py_DECREF (cadata_ascii );
2462+ if (r == -1 ) {
2463+ goto error ;
2464+ }
23542465 }
2355- else {
2356- _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
2466+ }
2467+
2468+ /* load cafile or capath */
2469+ if (cafile || capath ) {
2470+ if (cafile )
2471+ cafile_buf = PyBytes_AS_STRING (cafile_bytes );
2472+ if (capath )
2473+ capath_buf = PyBytes_AS_STRING (capath_bytes );
2474+ PySSL_BEGIN_ALLOW_THREADS
2475+ r = SSL_CTX_load_verify_locations (self -> ctx , cafile_buf , capath_buf );
2476+ PySSL_END_ALLOW_THREADS
2477+ if (r != 1 ) {
2478+ ok = 0 ;
2479+ if (errno != 0 ) {
2480+ ERR_clear_error ();
2481+ PyErr_SetFromErrno (PyExc_IOError );
2482+ }
2483+ else {
2484+ _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
2485+ }
2486+ goto error ;
23572487 }
2488+ }
2489+ goto end ;
2490+
2491+ error :
2492+ ok = 0 ;
2493+ end :
2494+ Py_XDECREF (cafile_bytes );
2495+ Py_XDECREF (capath_bytes );
2496+ if (ok ) {
2497+ Py_RETURN_NONE ;
2498+ } else {
23582499 return NULL ;
23592500 }
2360- Py_RETURN_NONE ;
23612501}
23622502
23632503static PyObject *
0 commit comments