OSDN Git Service

Add dialog to confirm certificate for SSL (experimental).
[ffftp/ffftp.git] / socketwrapper.c
1 // socketwrapper.c\r
2 // Copyright (C) 2011 Suguru Kawamoto\r
3 // ソケットラッパー\r
4 // socket関連関数をOpenSSL用に置換\r
5 // コンパイルにはOpenSSLのヘッダーファイルが必要\r
6 // 実行にはOpenSSLのDLLが必要\r
7 \r
8 #include <windows.h>\r
9 #include <mmsystem.h>\r
10 #include <openssl/ssl.h>\r
11 \r
12 #include "socketwrapper.h"\r
13 #include "protectprocess.h"\r
14 \r
15 typedef void (__cdecl* _SSL_load_error_strings)();\r
16 typedef int (__cdecl* _SSL_library_init)();\r
17 typedef SSL_METHOD* (__cdecl* _SSLv23_method)();\r
18 typedef SSL_CTX* (__cdecl* _SSL_CTX_new)(SSL_METHOD*);\r
19 typedef void (__cdecl* _SSL_CTX_free)(SSL_CTX*);\r
20 typedef SSL* (__cdecl* _SSL_new)(SSL_CTX*);\r
21 typedef void (__cdecl* _SSL_free)(SSL*);\r
22 typedef int (__cdecl* _SSL_shutdown)(SSL*);\r
23 typedef int (__cdecl* _SSL_get_fd)(SSL*);\r
24 typedef int (__cdecl* _SSL_set_fd)(SSL*, int);\r
25 typedef int (__cdecl* _SSL_accept)(SSL*);\r
26 typedef int (__cdecl* _SSL_connect)(SSL*);\r
27 typedef int (__cdecl* _SSL_write)(SSL*, const void*, int);\r
28 typedef int (__cdecl* _SSL_peek)(SSL*, void*, int);\r
29 typedef int (__cdecl* _SSL_read)(SSL*, void*, int);\r
30 typedef int (__cdecl* _SSL_get_error)(SSL*, int);\r
31 typedef X509* (__cdecl* _SSL_get_peer_certificate)(const SSL*);\r
32 typedef long (__cdecl* _SSL_get_verify_result)(const SSL*);\r
33 typedef BIO_METHOD* (__cdecl* _BIO_s_mem)();\r
34 typedef BIO* (__cdecl* _BIO_new)(BIO_METHOD*);\r
35 typedef int (__cdecl* _BIO_free)(BIO*);\r
36 typedef long (__cdecl* _BIO_ctrl)(BIO*, int, long, void*);\r
37 typedef void (__cdecl* _X509_free)(X509*);\r
38 typedef int (__cdecl* _X509_print_ex)(BIO*, X509*, unsigned long, unsigned long);\r
39 typedef X509_NAME* (__cdecl* _X509_get_subject_name)(X509*);\r
40 typedef X509_NAME* (__cdecl* _X509_get_issuer_name)(X509*);\r
41 typedef int (__cdecl* _X509_NAME_print_ex)(BIO*, X509_NAME*, int, unsigned long);\r
42 \r
43 _SSL_load_error_strings p_SSL_load_error_strings;\r
44 _SSL_library_init p_SSL_library_init;\r
45 _SSLv23_method p_SSLv23_method;\r
46 _SSL_CTX_new p_SSL_CTX_new;\r
47 _SSL_CTX_free p_SSL_CTX_free;\r
48 _SSL_new p_SSL_new;\r
49 _SSL_free p_SSL_free;\r
50 _SSL_shutdown p_SSL_shutdown;\r
51 _SSL_get_fd p_SSL_get_fd;\r
52 _SSL_set_fd p_SSL_set_fd;\r
53 _SSL_accept p_SSL_accept;\r
54 _SSL_connect p_SSL_connect;\r
55 _SSL_write p_SSL_write;\r
56 _SSL_peek p_SSL_peek;\r
57 _SSL_read p_SSL_read;\r
58 _SSL_get_error p_SSL_get_error;\r
59 _SSL_get_peer_certificate p_SSL_get_peer_certificate;\r
60 _SSL_get_verify_result p_SSL_get_verify_result;\r
61 _BIO_s_mem p_BIO_s_mem;\r
62 _BIO_new p_BIO_new;\r
63 _BIO_free p_BIO_free;\r
64 _BIO_ctrl p_BIO_ctrl;\r
65 _X509_free p_X509_free;\r
66 _X509_print_ex p_X509_print_ex;\r
67 _X509_get_subject_name p_X509_get_subject_name;\r
68 _X509_get_issuer_name p_X509_get_issuer_name;\r
69 _X509_NAME_print_ex p_X509_NAME_print_ex;\r
70 \r
71 #define MAX_SSL_SOCKET 64\r
72 \r
73 BOOL g_bOpenSSLLoaded;\r
74 HMODULE g_hOpenSSL;\r
75 HMODULE g_hOpenSSLCommon;\r
76 CRITICAL_SECTION g_OpenSSLLock;\r
77 DWORD g_OpenSSLTimeout;\r
78 LPSSLTIMEOUTCALLBACK g_pOpenSSLTimeoutCallback;\r
79 LPSSLCONFIRMCALLBACK g_pOpenSSLConfirmCallback;\r
80 SSL_CTX* g_pOpenSSLCTX;\r
81 SSL* g_pOpenSSLHandle[MAX_SSL_SOCKET];\r
82 \r
83 BOOL __stdcall DefaultSSLTimeoutCallback()\r
84 {\r
85         Sleep(100);\r
86         return FALSE;\r
87 }\r
88 \r
89 BOOL __stdcall DefaultSSLConfirmCallback(BOOL bVerified, LPCSTR Certificate, LPCSTR CommonName)\r
90 {\r
91         return bVerified;\r
92 }\r
93 \r
94 BOOL LoadOpenSSL()\r
95 {\r
96         if(g_bOpenSSLLoaded)\r
97                 return FALSE;\r
98 #ifdef ENABLE_PROCESS_PROTECTION\r
99         // 同梱するOpenSSLのバージョンに合わせてSHA1ハッシュ値を変更すること\r
100         // ssleay32.dll 1.0.0e\r
101         // libssl32.dll 1.0.0e\r
102         RegisterTrustedModuleSHA1Hash("\x4E\xB7\xA0\x22\x14\x4B\x58\x6D\xBC\xF5\x21\x0D\x96\x78\x0D\x79\x7D\x66\xB2\xB0");\r
103         // libeay32.dll 1.0.0e\r
104         RegisterTrustedModuleSHA1Hash("\x01\x32\x7A\xAE\x69\x26\xE6\x58\xC7\x63\x22\x1E\x53\x5A\x78\xBC\x61\xC7\xB5\xC1");\r
105 #endif\r
106         g_hOpenSSL = LoadLibrary("ssleay32.dll");\r
107         if(!g_hOpenSSL)\r
108                 g_hOpenSSL = LoadLibrary("libssl32.dll");\r
109         if(!g_hOpenSSL\r
110                 || !(p_SSL_load_error_strings = (_SSL_load_error_strings)GetProcAddress(g_hOpenSSL, "SSL_load_error_strings"))\r
111                 || !(p_SSL_library_init = (_SSL_library_init)GetProcAddress(g_hOpenSSL, "SSL_library_init"))\r
112                 || !(p_SSLv23_method = (_SSLv23_method)GetProcAddress(g_hOpenSSL, "SSLv23_method"))\r
113                 || !(p_SSL_CTX_new = (_SSL_CTX_new)GetProcAddress(g_hOpenSSL, "SSL_CTX_new"))\r
114                 || !(p_SSL_CTX_free = (_SSL_CTX_free)GetProcAddress(g_hOpenSSL, "SSL_CTX_free"))\r
115                 || !(p_SSL_new = (_SSL_new)GetProcAddress(g_hOpenSSL, "SSL_new"))\r
116                 || !(p_SSL_free = (_SSL_free)GetProcAddress(g_hOpenSSL, "SSL_free"))\r
117                 || !(p_SSL_shutdown = (_SSL_shutdown)GetProcAddress(g_hOpenSSL, "SSL_shutdown"))\r
118                 || !(p_SSL_get_fd = (_SSL_get_fd)GetProcAddress(g_hOpenSSL, "SSL_get_fd"))\r
119                 || !(p_SSL_set_fd = (_SSL_set_fd)GetProcAddress(g_hOpenSSL, "SSL_set_fd"))\r
120                 || !(p_SSL_accept = (_SSL_accept)GetProcAddress(g_hOpenSSL, "SSL_accept"))\r
121                 || !(p_SSL_connect = (_SSL_connect)GetProcAddress(g_hOpenSSL, "SSL_connect"))\r
122                 || !(p_SSL_write = (_SSL_write)GetProcAddress(g_hOpenSSL, "SSL_write"))\r
123                 || !(p_SSL_peek = (_SSL_peek)GetProcAddress(g_hOpenSSL, "SSL_peek"))\r
124                 || !(p_SSL_read = (_SSL_read)GetProcAddress(g_hOpenSSL, "SSL_read"))\r
125                 || !(p_SSL_get_error = (_SSL_get_error)GetProcAddress(g_hOpenSSL, "SSL_get_error"))\r
126                 || !(p_SSL_get_peer_certificate = (_SSL_get_peer_certificate)GetProcAddress(g_hOpenSSL, "SSL_get_peer_certificate"))\r
127                 || !(p_SSL_get_verify_result = (_SSL_get_verify_result)GetProcAddress(g_hOpenSSL, "SSL_get_verify_result")))\r
128         {\r
129                 if(g_hOpenSSL)\r
130                         FreeLibrary(g_hOpenSSL);\r
131                 g_hOpenSSL = NULL;\r
132                 return FALSE;\r
133         }\r
134         g_hOpenSSLCommon = LoadLibrary("libeay32.dll");\r
135         if(!g_hOpenSSLCommon\r
136                 || !(p_BIO_s_mem = (_BIO_s_mem)GetProcAddress(g_hOpenSSLCommon, "BIO_s_mem"))\r
137                 || !(p_BIO_new = (_BIO_new)GetProcAddress(g_hOpenSSLCommon, "BIO_new"))\r
138                 || !(p_BIO_free = (_BIO_free)GetProcAddress(g_hOpenSSLCommon, "BIO_free"))\r
139                 || !(p_BIO_ctrl = (_BIO_ctrl)GetProcAddress(g_hOpenSSLCommon, "BIO_ctrl"))\r
140                 || !(p_X509_free = (_X509_free)GetProcAddress(g_hOpenSSLCommon, "X509_free"))\r
141                 || !(p_X509_print_ex = (_X509_print_ex)GetProcAddress(g_hOpenSSLCommon, "X509_print_ex"))\r
142                 || !(p_X509_get_subject_name = (_X509_get_subject_name)GetProcAddress(g_hOpenSSLCommon, "X509_get_subject_name"))\r
143                 || !(p_X509_get_issuer_name = (_X509_get_issuer_name)GetProcAddress(g_hOpenSSLCommon, "X509_get_issuer_name"))\r
144                 || !(p_X509_NAME_print_ex = (_X509_NAME_print_ex)GetProcAddress(g_hOpenSSLCommon, "X509_NAME_print_ex")))\r
145         {\r
146                 if(g_hOpenSSL)\r
147                         FreeLibrary(g_hOpenSSL);\r
148                 g_hOpenSSL = NULL;\r
149                 if(g_hOpenSSLCommon)\r
150                         FreeLibrary(g_hOpenSSLCommon);\r
151                 g_hOpenSSLCommon = NULL;\r
152                 return FALSE;\r
153         }\r
154         InitializeCriticalSection(&g_OpenSSLLock);\r
155         p_SSL_load_error_strings();\r
156         p_SSL_library_init();\r
157         SetSSLTimeoutCallback(60000, DefaultSSLTimeoutCallback);\r
158         SetSSLConfirmCallback(DefaultSSLConfirmCallback);\r
159         g_bOpenSSLLoaded = TRUE;\r
160         return TRUE;\r
161 }\r
162 \r
163 void FreeOpenSSL()\r
164 {\r
165         int i;\r
166         if(!g_bOpenSSLLoaded)\r
167                 return;\r
168         EnterCriticalSection(&g_OpenSSLLock);\r
169         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
170         {\r
171                 if(g_pOpenSSLHandle[i])\r
172                 {\r
173                         p_SSL_shutdown(g_pOpenSSLHandle[i]);\r
174                         p_SSL_free(g_pOpenSSLHandle[i]);\r
175                         g_pOpenSSLHandle[i] = NULL;\r
176                 }\r
177         }\r
178         if(g_pOpenSSLCTX)\r
179                 p_SSL_CTX_free(g_pOpenSSLCTX);\r
180         g_pOpenSSLCTX = NULL;\r
181         FreeLibrary(g_hOpenSSL);\r
182         g_hOpenSSL = NULL;\r
183         FreeLibrary(g_hOpenSSLCommon);\r
184         g_hOpenSSLCommon = NULL;\r
185         LeaveCriticalSection(&g_OpenSSLLock);\r
186         DeleteCriticalSection(&g_OpenSSLLock);\r
187         g_bOpenSSLLoaded = FALSE;\r
188 }\r
189 \r
190 BOOL IsOpenSSLLoaded()\r
191 {\r
192         return g_bOpenSSLLoaded;\r
193 }\r
194 \r
195 SSL** GetUnusedSSLPointer()\r
196 {\r
197         int i;\r
198         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
199         {\r
200                 if(!g_pOpenSSLHandle[i])\r
201                         return &g_pOpenSSLHandle[i];\r
202         }\r
203         return NULL;\r
204 }\r
205 \r
206 SSL** FindSSLPointerFromSocket(SOCKET s)\r
207 {\r
208         int i;\r
209         for(i = 0; i < MAX_SSL_SOCKET; i++)\r
210         {\r
211                 if(g_pOpenSSLHandle[i])\r
212                 {\r
213                         if(p_SSL_get_fd(g_pOpenSSLHandle[i]) == s)\r
214                                 return &g_pOpenSSLHandle[i];\r
215                 }\r
216         }\r
217         return NULL;\r
218 }\r
219 \r
220 BOOL ConfirmSSLCertificate(SSL* pSSL)\r
221 {\r
222         BOOL bResult;\r
223         BOOL bVerified;\r
224         char* pData;\r
225         char* pSubject;\r
226         X509* pX509;\r
227         BIO* pBIO;\r
228         long Length;\r
229         char* pBuffer;\r
230         char* pCN;\r
231         char* p;\r
232         bResult = FALSE;\r
233         bVerified = FALSE;\r
234         pData = NULL;\r
235         pSubject = NULL;\r
236         if(pX509 = p_SSL_get_peer_certificate(pSSL))\r
237         {\r
238                 if(pBIO = p_BIO_new(p_BIO_s_mem()))\r
239                 {\r
240                         p_X509_print_ex(pBIO, pX509, 0, XN_FLAG_RFC2253);\r
241                         if((Length = p_BIO_ctrl(pBIO, BIO_CTRL_INFO, 0, &pBuffer)) > 0)\r
242                         {\r
243                                 if(pData = (char*)malloc(Length + sizeof(char)))\r
244                                 {\r
245                                         memcpy(pData, pBuffer, Length);\r
246                                         *(char*)((size_t)pData + Length) = '\0';\r
247                                 }\r
248                         }\r
249                         p_BIO_free(pBIO);\r
250                 }\r
251                 if(pBIO = p_BIO_new(p_BIO_s_mem()))\r
252                 {\r
253                         p_X509_NAME_print_ex(pBIO, p_X509_get_subject_name(pX509), 0, XN_FLAG_RFC2253);\r
254                         if((Length = p_BIO_ctrl(pBIO, BIO_CTRL_INFO, 0, &pBuffer)) > 0)\r
255                         {\r
256                                 if(pSubject = (char*)malloc(Length + sizeof(char)))\r
257                                 {\r
258                                         memcpy(pSubject, pBuffer, Length);\r
259                                         *(char*)((size_t)pSubject + Length) = '\0';\r
260                                 }\r
261                         }\r
262                         p_BIO_free(pBIO);\r
263                 }\r
264                 p_X509_free(pX509);\r
265         }\r
266         if(p_SSL_get_verify_result(pSSL) == X509_V_OK)\r
267                 bVerified = TRUE;\r
268         pCN = pSubject;\r
269         while(pCN)\r
270         {\r
271                 if(strncmp(pCN, "CN=", strlen("CN=")) == 0)\r
272                 {\r
273                         pCN += strlen("CN=");\r
274                         if(p = strchr(pCN, ','))\r
275                                 *p = '\0';\r
276                         break;\r
277                 }\r
278                 if(pCN = strchr(pCN, ','))\r
279                         pCN++;\r
280         }\r
281         bResult = g_pOpenSSLConfirmCallback(bVerified, pData, pCN);\r
282         if(pData)\r
283                 free(pData);\r
284         if(pSubject)\r
285                 free(pSubject);\r
286         return bResult;\r
287 }\r
288 \r
289 void SetSSLTimeoutCallback(DWORD Timeout, LPSSLTIMEOUTCALLBACK pCallback)\r
290 {\r
291         if(!g_bOpenSSLLoaded)\r
292                 return;\r
293         EnterCriticalSection(&g_OpenSSLLock);\r
294         g_OpenSSLTimeout = Timeout;\r
295         g_pOpenSSLTimeoutCallback = pCallback;\r
296         LeaveCriticalSection(&g_OpenSSLLock);\r
297 }\r
298 \r
299 void SetSSLConfirmCallback(LPSSLCONFIRMCALLBACK pCallback)\r
300 {\r
301         if(!g_bOpenSSLLoaded)\r
302                 return;\r
303         EnterCriticalSection(&g_OpenSSLLock);\r
304         g_pOpenSSLConfirmCallback = pCallback;\r
305         LeaveCriticalSection(&g_OpenSSLLock);\r
306 }\r
307 \r
308 BOOL IsHostNameMatched(LPCSTR HostName, LPCSTR CommonName)\r
309 {\r
310         BOOL bResult;\r
311         char* pAsterisk;\r
312         bResult = FALSE;\r
313         if(HostName && CommonName)\r
314         {\r
315                 if(pAsterisk = strchr(CommonName, '*'))\r
316                 {\r
317                         if(_strnicmp(HostName, CommonName, ((size_t)pAsterisk - (size_t)CommonName) / sizeof(char)) == 0)\r
318                         {\r
319                                 while(*pAsterisk == '*')\r
320                                 {\r
321                                         pAsterisk++;\r
322                                 }\r
323                                 if(_stricmp(HostName + strlen(HostName) - strlen(pAsterisk), pAsterisk) == 0)\r
324                                         bResult = TRUE;\r
325                         }\r
326                 }\r
327                 else if(_stricmp(HostName, CommonName) == 0)\r
328                         bResult = TRUE;\r
329         }\r
330         return bResult;\r
331 }\r
332 \r
333 BOOL AttachSSL(SOCKET s)\r
334 {\r
335         BOOL r;\r
336         DWORD Time;\r
337         SSL** ppSSL;\r
338         if(!g_bOpenSSLLoaded)\r
339                 return FALSE;\r
340         r = FALSE;\r
341         Time = timeGetTime();\r
342         EnterCriticalSection(&g_OpenSSLLock);\r
343         if(!g_pOpenSSLCTX)\r
344                 g_pOpenSSLCTX = p_SSL_CTX_new(p_SSLv23_method());\r
345         if(g_pOpenSSLCTX)\r
346         {\r
347                 if(ppSSL = GetUnusedSSLPointer())\r
348                 {\r
349                         if(*ppSSL = p_SSL_new(g_pOpenSSLCTX))\r
350                         {\r
351                                 if(p_SSL_set_fd(*ppSSL, s) != 0)\r
352                                 {\r
353                                         r = TRUE;\r
354                                         // SSLのネゴシエーションには時間がかかる場合がある\r
355                                         while(p_SSL_connect(*ppSSL) != 1)\r
356                                         {\r
357                                                 LeaveCriticalSection(&g_OpenSSLLock);\r
358                                                 if(g_pOpenSSLTimeoutCallback() || (g_OpenSSLTimeout > 0 && timeGetTime() - Time >= g_OpenSSLTimeout))\r
359                                                 {\r
360                                                         DetachSSL(s);\r
361                                                         r = FALSE;\r
362                                                         EnterCriticalSection(&g_OpenSSLLock);\r
363                                                         break;\r
364                                                 }\r
365                                                 EnterCriticalSection(&g_OpenSSLLock);\r
366                                         }\r
367                                 }\r
368                                 else\r
369                                 {\r
370                                         LeaveCriticalSection(&g_OpenSSLLock);\r
371                                         DetachSSL(s);\r
372                                         EnterCriticalSection(&g_OpenSSLLock);\r
373                                 }\r
374                                 if(ConfirmSSLCertificate(*ppSSL))\r
375                                 {\r
376                                 }\r
377                                 else\r
378                                 {\r
379                                         DetachSSL(s);\r
380                                         r = FALSE;\r
381                                 }\r
382                         }\r
383                 }\r
384         }\r
385         LeaveCriticalSection(&g_OpenSSLLock);\r
386         return r;\r
387 }\r
388 \r
389 BOOL DetachSSL(SOCKET s)\r
390 {\r
391         BOOL r;\r
392         SSL** ppSSL;\r
393         if(!g_bOpenSSLLoaded)\r
394                 return FALSE;\r
395         r = FALSE;\r
396         EnterCriticalSection(&g_OpenSSLLock);\r
397         if(ppSSL = FindSSLPointerFromSocket(s))\r
398         {\r
399                 p_SSL_shutdown(*ppSSL);\r
400                 p_SSL_free(*ppSSL);\r
401                 *ppSSL = NULL;\r
402                 r = TRUE;\r
403         }\r
404         LeaveCriticalSection(&g_OpenSSLLock);\r
405         return r;\r
406 }\r
407 \r
408 BOOL IsSSLAttached(SOCKET s)\r
409 {\r
410         SSL** ppSSL;\r
411         if(!g_bOpenSSLLoaded)\r
412                 return FALSE;\r
413         EnterCriticalSection(&g_OpenSSLLock);\r
414         ppSSL = FindSSLPointerFromSocket(s);\r
415         LeaveCriticalSection(&g_OpenSSLLock);\r
416         if(!ppSSL)\r
417                 return TRUE;\r
418         return TRUE;\r
419 }\r
420 \r
421 SOCKET socketS(int af, int type, int protocol)\r
422 {\r
423         return socket(af, type, protocol);\r
424 }\r
425 \r
426 int bindS(SOCKET s, const struct sockaddr *addr, int namelen)\r
427 {\r
428         return bind(s, addr, namelen);\r
429 }\r
430 \r
431 int listenS(SOCKET s, int backlog)\r
432 {\r
433         return listen(s, backlog);\r
434 }\r
435 \r
436 SOCKET acceptS(SOCKET s, struct sockaddr *addr, int *addrlen)\r
437 {\r
438         SOCKET r;\r
439         r = accept(s, addr, addrlen);\r
440         if(!AttachSSL(r))\r
441         {\r
442                 closesocket(r);\r
443                 return INVALID_SOCKET;\r
444         }\r
445         return r;\r
446 }\r
447 \r
448 int connectS(SOCKET s, const struct sockaddr *name, int namelen)\r
449 {\r
450         int r;\r
451         r = connect(s, name, namelen);\r
452         if(!AttachSSL(r))\r
453                 return SOCKET_ERROR;\r
454         return r;\r
455 }\r
456 \r
457 int closesocketS(SOCKET s)\r
458 {\r
459         DetachSSL(s);\r
460         return closesocket(s);\r
461 }\r
462 \r
463 int sendS(SOCKET s, const char * buf, int len, int flags)\r
464 {\r
465         SSL** ppSSL;\r
466         if(!g_bOpenSSLLoaded)\r
467                 return send(s, buf, len, flags);\r
468         EnterCriticalSection(&g_OpenSSLLock);\r
469         ppSSL = FindSSLPointerFromSocket(s);\r
470         LeaveCriticalSection(&g_OpenSSLLock);\r
471         if(!ppSSL)\r
472                 return send(s, buf, len, flags);\r
473         return p_SSL_write(*ppSSL, buf, len);\r
474 }\r
475 \r
476 int recvS(SOCKET s, char * buf, int len, int flags)\r
477 {\r
478         SSL** ppSSL;\r
479         if(!g_bOpenSSLLoaded)\r
480                 return recv(s, buf, len, flags);\r
481         EnterCriticalSection(&g_OpenSSLLock);\r
482         ppSSL = FindSSLPointerFromSocket(s);\r
483         LeaveCriticalSection(&g_OpenSSLLock);\r
484         if(!ppSSL)\r
485                 return recv(s, buf, len, flags);\r
486         if(flags & MSG_PEEK)\r
487                 return p_SSL_peek(*ppSSL, buf, len);\r
488         return p_SSL_read(*ppSSL, buf, len);\r
489 }\r
490 \r