1 /* Copyright (C) 2005 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 * This file implements the schannel provider, or, the SSL/TLS implementations.
18 * FIXME: It should be rather obvious that this file is empty of any
22 #include "wine/port.h"
25 #ifdef SONAME_LIBGNUTLS
26 #include <gnutls/gnutls.h>
34 #include "secur32_priv.h"
35 #include "wine/debug.h"
36 #include "wine/library.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(secur32
);
40 #ifdef SONAME_LIBGNUTLS
42 static void *libgnutls_handle
;
43 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
44 MAKE_FUNCPTR(gnutls_certificate_allocate_credentials
);
45 MAKE_FUNCPTR(gnutls_certificate_free_credentials
);
46 MAKE_FUNCPTR(gnutls_global_deinit
);
47 MAKE_FUNCPTR(gnutls_global_init
);
48 MAKE_FUNCPTR(gnutls_global_set_log_function
);
49 MAKE_FUNCPTR(gnutls_global_set_log_level
);
50 MAKE_FUNCPTR(gnutls_perror
);
53 #define SCHAN_INVALID_HANDLE ~0UL
55 enum schan_handle_type
64 enum schan_handle_type type
;
67 struct schan_credentials
70 gnutls_certificate_credentials credentials
;
73 static struct schan_handle
*schan_handle_table
;
74 static struct schan_handle
*schan_free_handles
;
75 static SIZE_T schan_handle_table_size
;
76 static SIZE_T schan_handle_count
;
78 static ULONG_PTR
schan_alloc_handle(void *object
, enum schan_handle_type type
)
80 struct schan_handle
*handle
;
82 if (schan_free_handles
)
84 /* Use a free handle */
85 handle
= schan_free_handles
;
86 if (handle
->type
!= SCHAN_HANDLE_FREE
)
88 ERR("Handle %d(%p) is in the free list, but has type %#x.\n", (handle
-schan_handle_table
), handle
, handle
->type
);
89 return SCHAN_INVALID_HANDLE
;
91 schan_free_handles
= (struct schan_handle
*)handle
->object
;
92 handle
->object
= object
;
95 return handle
- schan_handle_table
;
97 if (!(schan_handle_count
< schan_handle_table_size
))
100 SIZE_T new_size
= schan_handle_table_size
+ (schan_handle_table_size
>> 1);
101 struct schan_handle
*new_table
= HeapReAlloc(GetProcessHeap(), 0, schan_handle_table
, new_size
* sizeof(*schan_handle_table
));
104 ERR("Failed to grow the handle table\n");
105 return SCHAN_INVALID_HANDLE
;
107 schan_handle_table
= new_table
;
108 schan_handle_table_size
= new_size
;
111 handle
= &schan_handle_table
[schan_handle_count
++];
112 handle
->object
= object
;
115 return handle
- schan_handle_table
;
118 static void *schan_free_handle(ULONG_PTR handle_idx
, enum schan_handle_type type
)
120 struct schan_handle
*handle
;
123 if (handle_idx
== SCHAN_INVALID_HANDLE
) return NULL
;
124 handle
= &schan_handle_table
[handle_idx
];
125 if (handle
->type
!= type
)
127 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx
, handle
, type
);
131 object
= handle
->object
;
132 handle
->object
= schan_free_handles
;
133 handle
->type
= SCHAN_HANDLE_FREE
;
134 schan_free_handles
= handle
;
139 static SECURITY_STATUS
schan_QueryCredentialsAttributes(
140 PCredHandle phCredential
, ULONG ulAttribute
, const VOID
*pBuffer
)
146 case SECPKG_ATTR_SUPPORTED_ALGS
:
149 /* FIXME: get from CryptoAPI */
150 FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n");
151 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
154 ret
= SEC_E_INTERNAL_ERROR
;
156 case SECPKG_ATTR_CIPHER_STRENGTHS
:
159 SecPkgCred_CipherStrengths
*r
= (SecPkgCred_CipherStrengths
*)pBuffer
;
161 /* FIXME: get from CryptoAPI */
162 FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n");
163 r
->dwMinimumCipherStrength
= 40;
164 r
->dwMaximumCipherStrength
= 168;
168 ret
= SEC_E_INTERNAL_ERROR
;
170 case SECPKG_ATTR_SUPPORTED_PROTOCOLS
:
173 /* FIXME: get from OpenSSL? */
174 FIXME("SECPKG_ATTR_SUPPORTED_PROTOCOLS: stub\n");
175 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
178 ret
= SEC_E_INTERNAL_ERROR
;
181 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
186 static SECURITY_STATUS SEC_ENTRY
schan_QueryCredentialsAttributesA(
187 PCredHandle phCredential
, ULONG ulAttribute
, PVOID pBuffer
)
191 TRACE("(%p, %d, %p)\n", phCredential
, ulAttribute
, pBuffer
);
195 case SECPKG_CRED_ATTR_NAMES
:
196 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
197 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
200 ret
= schan_QueryCredentialsAttributes(phCredential
, ulAttribute
,
206 static SECURITY_STATUS SEC_ENTRY
schan_QueryCredentialsAttributesW(
207 PCredHandle phCredential
, ULONG ulAttribute
, PVOID pBuffer
)
211 TRACE("(%p, %d, %p)\n", phCredential
, ulAttribute
, pBuffer
);
215 case SECPKG_CRED_ATTR_NAMES
:
216 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
217 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
220 ret
= schan_QueryCredentialsAttributes(phCredential
, ulAttribute
,
226 static SECURITY_STATUS
schan_CheckCreds(const SCHANNEL_CRED
*schanCred
)
230 switch (schanCred
->dwVersion
)
233 case SCHANNEL_CRED_VERSION
:
236 return SEC_E_INTERNAL_ERROR
;
239 if (schanCred
->cCreds
== 0)
240 st
= SEC_E_NO_CREDENTIALS
;
241 else if (schanCred
->cCreds
> 1)
242 st
= SEC_E_UNKNOWN_CREDENTIALS
;
249 ret
= CryptAcquireCertificatePrivateKey(schanCred
->paCred
[0],
250 0, /* FIXME: what flags to use? */ NULL
,
251 &csp
, &keySpec
, &freeCSP
);
256 CryptReleaseContext(csp
, 0);
259 st
= SEC_E_UNKNOWN_CREDENTIALS
;
264 static SECURITY_STATUS
schan_AcquireClientCredentials(const SCHANNEL_CRED
*schanCred
,
265 PCredHandle phCredential
, PTimeStamp ptsExpiry
)
267 struct schan_credentials
*creds
;
268 SECURITY_STATUS st
= SEC_E_OK
;
270 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred
, phCredential
, ptsExpiry
);
274 st
= schan_CheckCreds(schanCred
);
275 if (st
== SEC_E_NO_CREDENTIALS
)
279 /* For now, the only thing I'm interested in is the direction of the
280 * connection, so just store it.
287 creds
= HeapAlloc(GetProcessHeap(), 0, sizeof(*creds
));
288 if (!creds
) return SEC_E_INSUFFICIENT_MEMORY
;
290 handle
= schan_alloc_handle(creds
, SCHAN_HANDLE_CRED
);
291 if (handle
== SCHAN_INVALID_HANDLE
) goto fail
;
293 creds
->credential_use
= SECPKG_CRED_OUTBOUND
;
294 ret
= pgnutls_certificate_allocate_credentials(&creds
->credentials
);
295 if (ret
!= GNUTLS_E_SUCCESS
)
301 phCredential
->dwLower
= handle
;
302 phCredential
->dwUpper
= 0;
304 /* Outbound credentials have no expiry */
307 ptsExpiry
->LowPart
= 0;
308 ptsExpiry
->HighPart
= 0;
314 HeapFree(GetProcessHeap(), 0, creds
);
315 return SEC_E_INTERNAL_ERROR
;
318 static SECURITY_STATUS
schan_AcquireServerCredentials(const SCHANNEL_CRED
*schanCred
,
319 PCredHandle phCredential
, PTimeStamp ptsExpiry
)
323 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred
, phCredential
, ptsExpiry
);
325 if (!schanCred
) return SEC_E_NO_CREDENTIALS
;
327 st
= schan_CheckCreds(schanCred
);
331 struct schan_credentials
*creds
;
333 creds
= HeapAlloc(GetProcessHeap(), 0, sizeof(*creds
));
334 if (!creds
) return SEC_E_INSUFFICIENT_MEMORY
;
335 creds
->credential_use
= SECPKG_CRED_INBOUND
;
337 handle
= schan_alloc_handle(creds
, SCHAN_HANDLE_CRED
);
338 if (handle
== SCHAN_INVALID_HANDLE
)
340 HeapFree(GetProcessHeap(), 0, creds
);
341 return SEC_E_INTERNAL_ERROR
;
344 phCredential
->dwLower
= handle
;
345 phCredential
->dwUpper
= 0;
347 /* FIXME: get expiry from cert */
352 static SECURITY_STATUS
schan_AcquireCredentialsHandle(ULONG fCredentialUse
,
353 const SCHANNEL_CRED
*schanCred
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
357 if (fCredentialUse
== SECPKG_CRED_OUTBOUND
)
358 ret
= schan_AcquireClientCredentials(schanCred
, phCredential
,
361 ret
= schan_AcquireServerCredentials(schanCred
, phCredential
,
366 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleA(
367 SEC_CHAR
*pszPrincipal
, SEC_CHAR
*pszPackage
, ULONG fCredentialUse
,
368 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
369 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
371 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
372 debugstr_a(pszPrincipal
), debugstr_a(pszPackage
), fCredentialUse
,
373 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
374 return schan_AcquireCredentialsHandle(fCredentialUse
,
375 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
378 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleW(
379 SEC_WCHAR
*pszPrincipal
, SEC_WCHAR
*pszPackage
, ULONG fCredentialUse
,
380 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
381 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
383 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
384 debugstr_w(pszPrincipal
), debugstr_w(pszPackage
), fCredentialUse
,
385 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
386 return schan_AcquireCredentialsHandle(fCredentialUse
,
387 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
390 static SECURITY_STATUS SEC_ENTRY
schan_FreeCredentialsHandle(
391 PCredHandle phCredential
)
393 struct schan_credentials
*creds
;
395 TRACE("phCredential %p\n", phCredential
);
397 if (!phCredential
) return SEC_E_INVALID_HANDLE
;
399 creds
= schan_free_handle(phCredential
->dwLower
, SCHAN_HANDLE_CRED
);
400 if (!creds
) return SEC_E_INVALID_HANDLE
;
402 if (creds
->credential_use
== SECPKG_CRED_OUTBOUND
)
403 pgnutls_certificate_free_credentials(creds
->credentials
);
404 HeapFree(GetProcessHeap(), 0, creds
);
409 /***********************************************************************
410 * InitializeSecurityContextW
412 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextW(
413 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_WCHAR
*pszTargetName
,
414 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
415 PSecBufferDesc pInput
, ULONG Reserved2
, PCtxtHandle phNewContext
,
416 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
420 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
421 debugstr_w(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
422 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
426 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
430 ret
= SEC_E_INVALID_HANDLE
;
435 /***********************************************************************
436 * InitializeSecurityContextA
438 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextA(
439 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_CHAR
*pszTargetName
,
440 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
441 PSecBufferDesc pInput
, ULONG Reserved2
, PCtxtHandle phNewContext
,
442 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
445 SEC_WCHAR
*target_name
= NULL
;
447 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
448 debugstr_a(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
449 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
453 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszTargetName
, -1, NULL
, 0);
454 target_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(*target_name
));
455 MultiByteToWideChar(CP_ACP
, 0, pszTargetName
, -1, target_name
, len
);
458 ret
= schan_InitializeSecurityContextW(phCredential
, phContext
, target_name
,
459 fContextReq
, Reserved1
, TargetDataRep
, pInput
, Reserved2
,
460 phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
462 HeapFree(GetProcessHeap(), 0, target_name
);
467 static void schan_gnutls_log(int level
, const char *msg
)
469 TRACE("<%d> %s", level
, msg
);
472 static const SecurityFunctionTableA schanTableA
= {
474 NULL
, /* EnumerateSecurityPackagesA */
475 schan_QueryCredentialsAttributesA
,
476 schan_AcquireCredentialsHandleA
,
477 schan_FreeCredentialsHandle
,
478 NULL
, /* Reserved2 */
479 schan_InitializeSecurityContextA
,
480 NULL
, /* AcceptSecurityContext */
481 NULL
, /* CompleteAuthToken */
482 NULL
, /* DeleteSecurityContext */
483 NULL
, /* ApplyControlToken */
484 NULL
, /* QueryContextAttributesA */
485 NULL
, /* ImpersonateSecurityContext */
486 NULL
, /* RevertSecurityContext */
487 NULL
, /* MakeSignature */
488 NULL
, /* VerifySignature */
490 NULL
, /* QuerySecurityPackageInfoA */
491 NULL
, /* Reserved3 */
492 NULL
, /* Reserved4 */
493 NULL
, /* ExportSecurityContext */
494 NULL
, /* ImportSecurityContextA */
495 NULL
, /* AddCredentialsA */
496 NULL
, /* Reserved8 */
497 NULL
, /* QuerySecurityContextToken */
498 NULL
, /* EncryptMessage */
499 NULL
, /* DecryptMessage */
500 NULL
, /* SetContextAttributesA */
503 static const SecurityFunctionTableW schanTableW
= {
505 NULL
, /* EnumerateSecurityPackagesW */
506 schan_QueryCredentialsAttributesW
,
507 schan_AcquireCredentialsHandleW
,
508 schan_FreeCredentialsHandle
,
509 NULL
, /* Reserved2 */
510 schan_InitializeSecurityContextW
,
511 NULL
, /* AcceptSecurityContext */
512 NULL
, /* CompleteAuthToken */
513 NULL
, /* DeleteSecurityContext */
514 NULL
, /* ApplyControlToken */
515 NULL
, /* QueryContextAttributesW */
516 NULL
, /* ImpersonateSecurityContext */
517 NULL
, /* RevertSecurityContext */
518 NULL
, /* MakeSignature */
519 NULL
, /* VerifySignature */
521 NULL
, /* QuerySecurityPackageInfoW */
522 NULL
, /* Reserved3 */
523 NULL
, /* Reserved4 */
524 NULL
, /* ExportSecurityContext */
525 NULL
, /* ImportSecurityContextW */
526 NULL
, /* AddCredentialsW */
527 NULL
, /* Reserved8 */
528 NULL
, /* QuerySecurityContextToken */
529 NULL
, /* EncryptMessage */
530 NULL
, /* DecryptMessage */
531 NULL
, /* SetContextAttributesW */
534 static const WCHAR schannelComment
[] = { 'S','c','h','a','n','n','e','l',' ',
535 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
536 static const WCHAR schannelDllName
[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
538 void SECUR32_initSchannelSP(void)
540 SecureProvider
*provider
;
543 libgnutls_handle
= wine_dlopen(SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0);
544 if (!libgnutls_handle
)
546 WARN("Failed to load libgnutls.\n");
550 #define LOAD_FUNCPTR(f) \
551 if (!(p##f = wine_dlsym(libgnutls_handle, #f, NULL, 0))) \
553 ERR("Failed to load %s\n", #f); \
554 wine_dlclose(libgnutls_handle, NULL, 0); \
555 libgnutls_handle = NULL; \
559 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials
)
560 LOAD_FUNCPTR(gnutls_certificate_free_credentials
)
561 LOAD_FUNCPTR(gnutls_global_deinit
)
562 LOAD_FUNCPTR(gnutls_global_init
)
563 LOAD_FUNCPTR(gnutls_global_set_log_function
)
564 LOAD_FUNCPTR(gnutls_global_set_log_level
)
565 LOAD_FUNCPTR(gnutls_perror
)
568 provider
= SECUR32_addProvider(&schanTableA
, &schanTableW
, schannelDllName
);
572 /* This is what Windows reports. This shouldn't break any applications
573 * even though the functions are missing, because the wrapper will
574 * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
576 static const long caps
=
577 SECPKG_FLAG_INTEGRITY
|
578 SECPKG_FLAG_PRIVACY
|
579 SECPKG_FLAG_CONNECTION
|
580 SECPKG_FLAG_MULTI_REQUIRED
|
581 SECPKG_FLAG_EXTENDED_ERROR
|
582 SECPKG_FLAG_IMPERSONATION
|
583 SECPKG_FLAG_ACCEPT_WIN32_NAME
|
585 static const short version
= 1;
586 static const long maxToken
= 16384;
587 SEC_WCHAR
*uniSPName
= (SEC_WCHAR
*)UNISP_NAME_W
,
588 *schannel
= (SEC_WCHAR
*)SCHANNEL_NAME_W
;
590 const SecPkgInfoW info
[] = {
591 { caps
, version
, UNISP_RPC_ID
, maxToken
, uniSPName
, uniSPName
},
592 { caps
, version
, UNISP_RPC_ID
, maxToken
, schannel
,
593 (SEC_WCHAR
*)schannelComment
},
596 SECUR32_addPackages(provider
, sizeof(info
) / sizeof(info
[0]), NULL
,
599 schan_handle_table
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 64 * sizeof(*schan_handle_table
));
600 schan_handle_table_size
= 64;
602 pgnutls_global_init();
603 if (TRACE_ON(secur32
))
605 pgnutls_global_set_log_level(4);
606 pgnutls_global_set_log_function(schan_gnutls_log
);
611 void SECUR32_deinitSchannelSP(void)
613 pgnutls_global_deinit();
614 if (libgnutls_handle
) wine_dlclose(libgnutls_handle
, NULL
, 0);
617 #else /* SONAME_LIBGNUTLS */
619 void SECUR32_initSchannelSP(void) {}
620 void SECUR32_deinitSchannelSP(void) {}
622 #endif /* SONAME_LIBGNUTLS */