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
, 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
)
298 schan_free_handle(handle
, SCHAN_HANDLE_CRED
);
302 phCredential
->dwLower
= handle
;
303 phCredential
->dwUpper
= 0;
305 /* Outbound credentials have no expiry */
308 ptsExpiry
->LowPart
= 0;
309 ptsExpiry
->HighPart
= 0;
315 HeapFree(GetProcessHeap(), 0, creds
);
316 return SEC_E_INTERNAL_ERROR
;
319 static SECURITY_STATUS
schan_AcquireServerCredentials(const SCHANNEL_CRED
*schanCred
,
320 PCredHandle phCredential
, PTimeStamp ptsExpiry
)
324 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred
, phCredential
, ptsExpiry
);
326 if (!schanCred
) return SEC_E_NO_CREDENTIALS
;
328 st
= schan_CheckCreds(schanCred
);
332 struct schan_credentials
*creds
;
334 creds
= HeapAlloc(GetProcessHeap(), 0, sizeof(*creds
));
335 if (!creds
) return SEC_E_INSUFFICIENT_MEMORY
;
336 creds
->credential_use
= SECPKG_CRED_INBOUND
;
338 handle
= schan_alloc_handle(creds
, SCHAN_HANDLE_CRED
);
339 if (handle
== SCHAN_INVALID_HANDLE
)
341 HeapFree(GetProcessHeap(), 0, creds
);
342 return SEC_E_INTERNAL_ERROR
;
345 phCredential
->dwLower
= handle
;
346 phCredential
->dwUpper
= 0;
348 /* FIXME: get expiry from cert */
353 static SECURITY_STATUS
schan_AcquireCredentialsHandle(ULONG fCredentialUse
,
354 const SCHANNEL_CRED
*schanCred
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
358 if (fCredentialUse
== SECPKG_CRED_OUTBOUND
)
359 ret
= schan_AcquireClientCredentials(schanCred
, phCredential
,
362 ret
= schan_AcquireServerCredentials(schanCred
, phCredential
,
367 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleA(
368 SEC_CHAR
*pszPrincipal
, SEC_CHAR
*pszPackage
, ULONG fCredentialUse
,
369 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
370 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
372 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
373 debugstr_a(pszPrincipal
), debugstr_a(pszPackage
), fCredentialUse
,
374 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
375 return schan_AcquireCredentialsHandle(fCredentialUse
,
376 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
379 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleW(
380 SEC_WCHAR
*pszPrincipal
, SEC_WCHAR
*pszPackage
, ULONG fCredentialUse
,
381 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
382 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
384 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
385 debugstr_w(pszPrincipal
), debugstr_w(pszPackage
), fCredentialUse
,
386 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
387 return schan_AcquireCredentialsHandle(fCredentialUse
,
388 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
391 static SECURITY_STATUS SEC_ENTRY
schan_FreeCredentialsHandle(
392 PCredHandle phCredential
)
394 struct schan_credentials
*creds
;
396 TRACE("phCredential %p\n", phCredential
);
398 if (!phCredential
) return SEC_E_INVALID_HANDLE
;
400 creds
= schan_free_handle(phCredential
->dwLower
, SCHAN_HANDLE_CRED
);
401 if (!creds
) return SEC_E_INVALID_HANDLE
;
403 if (creds
->credential_use
== SECPKG_CRED_OUTBOUND
)
404 pgnutls_certificate_free_credentials(creds
->credentials
);
405 HeapFree(GetProcessHeap(), 0, creds
);
410 /***********************************************************************
411 * InitializeSecurityContextW
413 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextW(
414 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_WCHAR
*pszTargetName
,
415 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
416 PSecBufferDesc pInput
, ULONG Reserved2
, PCtxtHandle phNewContext
,
417 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
421 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
422 debugstr_w(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
423 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
427 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
431 ret
= SEC_E_INVALID_HANDLE
;
436 /***********************************************************************
437 * InitializeSecurityContextA
439 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextA(
440 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_CHAR
*pszTargetName
,
441 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
442 PSecBufferDesc pInput
, ULONG Reserved2
, PCtxtHandle phNewContext
,
443 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
446 SEC_WCHAR
*target_name
= NULL
;
448 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
449 debugstr_a(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
450 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
454 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszTargetName
, -1, NULL
, 0);
455 target_name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(*target_name
));
456 MultiByteToWideChar(CP_ACP
, 0, pszTargetName
, -1, target_name
, len
);
459 ret
= schan_InitializeSecurityContextW(phCredential
, phContext
, target_name
,
460 fContextReq
, Reserved1
, TargetDataRep
, pInput
, Reserved2
,
461 phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
463 HeapFree(GetProcessHeap(), 0, target_name
);
468 static void schan_gnutls_log(int level
, const char *msg
)
470 TRACE("<%d> %s", level
, msg
);
473 static const SecurityFunctionTableA schanTableA
= {
475 NULL
, /* EnumerateSecurityPackagesA */
476 schan_QueryCredentialsAttributesA
,
477 schan_AcquireCredentialsHandleA
,
478 schan_FreeCredentialsHandle
,
479 NULL
, /* Reserved2 */
480 schan_InitializeSecurityContextA
,
481 NULL
, /* AcceptSecurityContext */
482 NULL
, /* CompleteAuthToken */
483 NULL
, /* DeleteSecurityContext */
484 NULL
, /* ApplyControlToken */
485 NULL
, /* QueryContextAttributesA */
486 NULL
, /* ImpersonateSecurityContext */
487 NULL
, /* RevertSecurityContext */
488 NULL
, /* MakeSignature */
489 NULL
, /* VerifySignature */
491 NULL
, /* QuerySecurityPackageInfoA */
492 NULL
, /* Reserved3 */
493 NULL
, /* Reserved4 */
494 NULL
, /* ExportSecurityContext */
495 NULL
, /* ImportSecurityContextA */
496 NULL
, /* AddCredentialsA */
497 NULL
, /* Reserved8 */
498 NULL
, /* QuerySecurityContextToken */
499 NULL
, /* EncryptMessage */
500 NULL
, /* DecryptMessage */
501 NULL
, /* SetContextAttributesA */
504 static const SecurityFunctionTableW schanTableW
= {
506 NULL
, /* EnumerateSecurityPackagesW */
507 schan_QueryCredentialsAttributesW
,
508 schan_AcquireCredentialsHandleW
,
509 schan_FreeCredentialsHandle
,
510 NULL
, /* Reserved2 */
511 schan_InitializeSecurityContextW
,
512 NULL
, /* AcceptSecurityContext */
513 NULL
, /* CompleteAuthToken */
514 NULL
, /* DeleteSecurityContext */
515 NULL
, /* ApplyControlToken */
516 NULL
, /* QueryContextAttributesW */
517 NULL
, /* ImpersonateSecurityContext */
518 NULL
, /* RevertSecurityContext */
519 NULL
, /* MakeSignature */
520 NULL
, /* VerifySignature */
522 NULL
, /* QuerySecurityPackageInfoW */
523 NULL
, /* Reserved3 */
524 NULL
, /* Reserved4 */
525 NULL
, /* ExportSecurityContext */
526 NULL
, /* ImportSecurityContextW */
527 NULL
, /* AddCredentialsW */
528 NULL
, /* Reserved8 */
529 NULL
, /* QuerySecurityContextToken */
530 NULL
, /* EncryptMessage */
531 NULL
, /* DecryptMessage */
532 NULL
, /* SetContextAttributesW */
535 static const WCHAR schannelComment
[] = { 'S','c','h','a','n','n','e','l',' ',
536 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
537 static const WCHAR schannelDllName
[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
539 void SECUR32_initSchannelSP(void)
541 SecureProvider
*provider
;
544 libgnutls_handle
= wine_dlopen(SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0);
545 if (!libgnutls_handle
)
547 WARN("Failed to load libgnutls.\n");
551 #define LOAD_FUNCPTR(f) \
552 if (!(p##f = wine_dlsym(libgnutls_handle, #f, NULL, 0))) \
554 ERR("Failed to load %s\n", #f); \
555 wine_dlclose(libgnutls_handle, NULL, 0); \
556 libgnutls_handle = NULL; \
560 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials
)
561 LOAD_FUNCPTR(gnutls_certificate_free_credentials
)
562 LOAD_FUNCPTR(gnutls_global_deinit
)
563 LOAD_FUNCPTR(gnutls_global_init
)
564 LOAD_FUNCPTR(gnutls_global_set_log_function
)
565 LOAD_FUNCPTR(gnutls_global_set_log_level
)
566 LOAD_FUNCPTR(gnutls_perror
)
569 provider
= SECUR32_addProvider(&schanTableA
, &schanTableW
, schannelDllName
);
573 /* This is what Windows reports. This shouldn't break any applications
574 * even though the functions are missing, because the wrapper will
575 * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
577 static const long caps
=
578 SECPKG_FLAG_INTEGRITY
|
579 SECPKG_FLAG_PRIVACY
|
580 SECPKG_FLAG_CONNECTION
|
581 SECPKG_FLAG_MULTI_REQUIRED
|
582 SECPKG_FLAG_EXTENDED_ERROR
|
583 SECPKG_FLAG_IMPERSONATION
|
584 SECPKG_FLAG_ACCEPT_WIN32_NAME
|
586 static const short version
= 1;
587 static const long maxToken
= 16384;
588 SEC_WCHAR
*uniSPName
= (SEC_WCHAR
*)UNISP_NAME_W
,
589 *schannel
= (SEC_WCHAR
*)SCHANNEL_NAME_W
;
591 const SecPkgInfoW info
[] = {
592 { caps
, version
, UNISP_RPC_ID
, maxToken
, uniSPName
, uniSPName
},
593 { caps
, version
, UNISP_RPC_ID
, maxToken
, schannel
,
594 (SEC_WCHAR
*)schannelComment
},
597 SECUR32_addPackages(provider
, sizeof(info
) / sizeof(info
[0]), NULL
,
600 schan_handle_table
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 64 * sizeof(*schan_handle_table
));
601 schan_handle_table_size
= 64;
603 pgnutls_global_init();
604 if (TRACE_ON(secur32
))
606 pgnutls_global_set_log_level(4);
607 pgnutls_global_set_log_function(schan_gnutls_log
);
612 void SECUR32_deinitSchannelSP(void)
614 pgnutls_global_deinit();
615 if (libgnutls_handle
) wine_dlclose(libgnutls_handle
, NULL
, 0);
618 #else /* SONAME_LIBGNUTLS */
620 void SECUR32_initSchannelSP(void) {}
621 void SECUR32_deinitSchannelSP(void) {}
623 #endif /* SONAME_LIBGNUTLS */