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>
33 #include "secur32_priv.h"
34 #include "wine/debug.h"
35 #include "wine/library.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(secur32
);
39 #ifdef SONAME_LIBGNUTLS
41 static void *libgnutls_handle
;
42 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
43 MAKE_FUNCPTR(gnutls_certificate_allocate_credentials
);
44 MAKE_FUNCPTR(gnutls_certificate_free_credentials
);
45 MAKE_FUNCPTR(gnutls_global_deinit
);
46 MAKE_FUNCPTR(gnutls_global_init
);
47 MAKE_FUNCPTR(gnutls_global_set_log_function
);
48 MAKE_FUNCPTR(gnutls_global_set_log_level
);
51 enum schan_handle_type
60 enum schan_handle_type type
;
63 struct schan_credentials
66 gnutls_certificate_credentials credentials
;
69 static struct schan_handle
*schan_handle_table
;
70 static struct schan_handle
*schan_free_handles
;
71 static SIZE_T schan_handle_table_size
;
72 static SIZE_T schan_handle_count
;
74 static ULONG_PTR
schan_alloc_handle(void *object
, enum schan_handle_type type
)
76 struct schan_handle
*handle
;
78 if (schan_free_handles
)
80 /* Use a free handle */
81 handle
= schan_free_handles
;
82 if (handle
->type
!= SCHAN_HANDLE_FREE
)
84 ERR("Handle %d(%p) is in the free list, but has type %#x.\n", (handle
-schan_handle_table
), handle
, handle
->type
);
87 schan_free_handles
= (struct schan_handle
*)handle
->object
;
88 handle
->object
= object
;
91 return handle
- schan_handle_table
;
93 if (!(schan_handle_count
< schan_handle_table_size
))
96 SIZE_T new_size
= schan_handle_table_size
+ (schan_handle_table_size
>> 1);
97 struct schan_handle
*new_table
= HeapReAlloc(GetProcessHeap(), 0, schan_handle_table
, new_size
* sizeof(*schan_handle_table
));
100 ERR("Failed to grow the handle table\n");
103 schan_handle_table
= new_table
;
104 schan_handle_table_size
= new_size
;
107 handle
= &schan_handle_table
[schan_handle_count
++];
108 handle
->object
= object
;
111 return handle
- schan_handle_table
;
114 static void *schan_free_handle(ULONG_PTR handle_idx
, enum schan_handle_type type
)
116 struct schan_handle
*handle
;
119 if (handle_idx
== -1) return NULL
;
120 handle
= &schan_handle_table
[handle_idx
];
121 if (handle
->type
!= type
)
123 ERR("Handle %ld(%p) is not of type %#x\n", handle_idx
, handle
, type
);
127 object
= handle
->object
;
128 handle
->object
= schan_free_handles
;
129 handle
->type
= SCHAN_HANDLE_FREE
;
130 schan_free_handles
= handle
;
135 static SECURITY_STATUS
schan_QueryCredentialsAttributes(
136 PCredHandle phCredential
, ULONG ulAttribute
, const VOID
*pBuffer
)
142 case SECPKG_ATTR_SUPPORTED_ALGS
:
145 /* FIXME: get from CryptoAPI */
146 FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n");
147 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
150 ret
= SEC_E_INTERNAL_ERROR
;
152 case SECPKG_ATTR_CIPHER_STRENGTHS
:
155 SecPkgCred_CipherStrengths
*r
= (SecPkgCred_CipherStrengths
*)pBuffer
;
157 /* FIXME: get from CryptoAPI */
158 FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n");
159 r
->dwMinimumCipherStrength
= 40;
160 r
->dwMaximumCipherStrength
= 168;
164 ret
= SEC_E_INTERNAL_ERROR
;
166 case SECPKG_ATTR_SUPPORTED_PROTOCOLS
:
169 /* FIXME: get from OpenSSL? */
170 FIXME("SECPKG_ATTR_SUPPORTED_PROTOCOLS: stub\n");
171 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
174 ret
= SEC_E_INTERNAL_ERROR
;
177 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
182 static SECURITY_STATUS SEC_ENTRY
schan_QueryCredentialsAttributesA(
183 PCredHandle phCredential
, ULONG ulAttribute
, PVOID pBuffer
)
187 TRACE("(%p, %d, %p)\n", phCredential
, ulAttribute
, pBuffer
);
191 case SECPKG_CRED_ATTR_NAMES
:
192 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
193 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
196 ret
= schan_QueryCredentialsAttributes(phCredential
, ulAttribute
,
202 static SECURITY_STATUS SEC_ENTRY
schan_QueryCredentialsAttributesW(
203 PCredHandle phCredential
, ULONG ulAttribute
, PVOID pBuffer
)
207 TRACE("(%p, %d, %p)\n", phCredential
, ulAttribute
, pBuffer
);
211 case SECPKG_CRED_ATTR_NAMES
:
212 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
213 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
216 ret
= schan_QueryCredentialsAttributes(phCredential
, ulAttribute
,
222 static SECURITY_STATUS
schan_CheckCreds(const SCHANNEL_CRED
*schanCred
)
226 switch (schanCred
->dwVersion
)
229 case SCHANNEL_CRED_VERSION
:
232 return SEC_E_INTERNAL_ERROR
;
235 if (schanCred
->cCreds
== 0)
236 st
= SEC_E_NO_CREDENTIALS
;
237 else if (schanCred
->cCreds
> 1)
238 st
= SEC_E_UNKNOWN_CREDENTIALS
;
245 ret
= CryptAcquireCertificatePrivateKey(schanCred
->paCred
[0],
246 0, /* FIXME: what flags to use? */ NULL
,
247 &csp
, &keySpec
, &freeCSP
);
252 CryptReleaseContext(csp
, 0);
255 st
= SEC_E_UNKNOWN_CREDENTIALS
;
260 static SECURITY_STATUS
schan_AcquireClientCredentials(const SCHANNEL_CRED
*schanCred
,
261 PCredHandle phCredential
, PTimeStamp ptsExpiry
)
263 SECURITY_STATUS st
= SEC_E_OK
;
265 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred
, phCredential
, ptsExpiry
);
269 st
= schan_CheckCreds(schanCred
);
270 if (st
== SEC_E_NO_CREDENTIALS
)
274 /* For now, the only thing I'm interested in is the direction of the
275 * connection, so just store it.
280 struct schan_credentials
*creds
;
282 creds
= HeapAlloc(GetProcessHeap(), 0, sizeof(*creds
));
283 if (!creds
) return SEC_E_INSUFFICIENT_MEMORY
;
285 handle
= schan_alloc_handle(creds
, SCHAN_HANDLE_CRED
);
288 HeapFree(GetProcessHeap(), 0, creds
);
289 return SEC_E_INTERNAL_ERROR
;
292 creds
->credential_use
= SECPKG_CRED_OUTBOUND
;
293 pgnutls_certificate_allocate_credentials(&creds
->credentials
);
295 phCredential
->dwLower
= handle
;
296 phCredential
->dwUpper
= 0;
298 /* Outbound credentials have no expiry */
301 ptsExpiry
->LowPart
= 0;
302 ptsExpiry
->HighPart
= 0;
308 static SECURITY_STATUS
schan_AcquireServerCredentials(const SCHANNEL_CRED
*schanCred
,
309 PCredHandle phCredential
, PTimeStamp ptsExpiry
)
313 TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred
, phCredential
, ptsExpiry
);
315 if (!schanCred
) return SEC_E_NO_CREDENTIALS
;
317 st
= schan_CheckCreds(schanCred
);
321 struct schan_credentials
*creds
;
323 creds
= HeapAlloc(GetProcessHeap(), 0, sizeof(*creds
));
324 if (!creds
) return SEC_E_INSUFFICIENT_MEMORY
;
325 creds
->credential_use
= SECPKG_CRED_INBOUND
;
327 handle
= schan_alloc_handle(creds
, SCHAN_HANDLE_CRED
);
330 HeapFree(GetProcessHeap(), 0, creds
);
331 return SEC_E_INTERNAL_ERROR
;
334 phCredential
->dwLower
= handle
;
335 phCredential
->dwUpper
= 0;
337 /* FIXME: get expiry from cert */
342 static SECURITY_STATUS
schan_AcquireCredentialsHandle(ULONG fCredentialUse
,
343 const SCHANNEL_CRED
*schanCred
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
347 if (fCredentialUse
== SECPKG_CRED_OUTBOUND
)
348 ret
= schan_AcquireClientCredentials(schanCred
, phCredential
,
351 ret
= schan_AcquireServerCredentials(schanCred
, phCredential
,
356 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleA(
357 SEC_CHAR
*pszPrincipal
, SEC_CHAR
*pszPackage
, ULONG fCredentialUse
,
358 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
359 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
361 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
362 debugstr_a(pszPrincipal
), debugstr_a(pszPackage
), fCredentialUse
,
363 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
364 return schan_AcquireCredentialsHandle(fCredentialUse
,
365 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
368 static SECURITY_STATUS SEC_ENTRY
schan_AcquireCredentialsHandleW(
369 SEC_WCHAR
*pszPrincipal
, SEC_WCHAR
*pszPackage
, ULONG fCredentialUse
,
370 PLUID pLogonID
, PVOID pAuthData
, SEC_GET_KEY_FN pGetKeyFn
,
371 PVOID pGetKeyArgument
, PCredHandle phCredential
, PTimeStamp ptsExpiry
)
373 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
374 debugstr_w(pszPrincipal
), debugstr_w(pszPackage
), fCredentialUse
,
375 pLogonID
, pAuthData
, pGetKeyFn
, pGetKeyArgument
, phCredential
, ptsExpiry
);
376 return schan_AcquireCredentialsHandle(fCredentialUse
,
377 (PSCHANNEL_CRED
)pAuthData
, phCredential
, ptsExpiry
);
380 static SECURITY_STATUS SEC_ENTRY
schan_FreeCredentialsHandle(
381 PCredHandle phCredential
)
383 struct schan_credentials
*creds
;
385 TRACE("phCredential %p\n", phCredential
);
387 if (!phCredential
) return SEC_E_INVALID_HANDLE
;
389 creds
= schan_free_handle(phCredential
->dwLower
, SCHAN_HANDLE_CRED
);
390 if (!creds
) return SEC_E_INVALID_HANDLE
;
392 if (creds
->credential_use
== SECPKG_CRED_OUTBOUND
)
393 pgnutls_certificate_free_credentials(creds
->credentials
);
394 HeapFree(GetProcessHeap(), 0, creds
);
399 /***********************************************************************
400 * InitializeSecurityContextA
402 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextA(
403 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_CHAR
*pszTargetName
,
404 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
405 PSecBufferDesc pInput
, ULONG Reserved2
, PCtxtHandle phNewContext
,
406 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
410 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
411 debugstr_a(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
412 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
416 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
420 ret
= SEC_E_INVALID_HANDLE
;
425 /***********************************************************************
426 * InitializeSecurityContextW
428 static SECURITY_STATUS SEC_ENTRY
schan_InitializeSecurityContextW(
429 PCredHandle phCredential
, PCtxtHandle phContext
, SEC_WCHAR
*pszTargetName
,
430 ULONG fContextReq
, ULONG Reserved1
, ULONG TargetDataRep
,
431 PSecBufferDesc pInput
,ULONG Reserved2
, PCtxtHandle phNewContext
,
432 PSecBufferDesc pOutput
, ULONG
*pfContextAttr
, PTimeStamp ptsExpiry
)
436 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential
, phContext
,
437 debugstr_w(pszTargetName
), fContextReq
, Reserved1
, TargetDataRep
, pInput
,
438 Reserved1
, phNewContext
, pOutput
, pfContextAttr
, ptsExpiry
);
442 ret
= SEC_E_UNSUPPORTED_FUNCTION
;
446 ret
= SEC_E_INVALID_HANDLE
;
451 static void schan_gnutls_log(int level
, const char *msg
)
453 TRACE("<%d> %s", level
, msg
);
456 static const SecurityFunctionTableA schanTableA
= {
458 NULL
, /* EnumerateSecurityPackagesA */
459 schan_QueryCredentialsAttributesA
,
460 schan_AcquireCredentialsHandleA
,
461 schan_FreeCredentialsHandle
,
462 NULL
, /* Reserved2 */
463 schan_InitializeSecurityContextA
,
464 NULL
, /* AcceptSecurityContext */
465 NULL
, /* CompleteAuthToken */
466 NULL
, /* DeleteSecurityContext */
467 NULL
, /* ApplyControlToken */
468 NULL
, /* QueryContextAttributesA */
469 NULL
, /* ImpersonateSecurityContext */
470 NULL
, /* RevertSecurityContext */
471 NULL
, /* MakeSignature */
472 NULL
, /* VerifySignature */
474 NULL
, /* QuerySecurityPackageInfoA */
475 NULL
, /* Reserved3 */
476 NULL
, /* Reserved4 */
477 NULL
, /* ExportSecurityContext */
478 NULL
, /* ImportSecurityContextA */
479 NULL
, /* AddCredentialsA */
480 NULL
, /* Reserved8 */
481 NULL
, /* QuerySecurityContextToken */
482 NULL
, /* EncryptMessage */
483 NULL
, /* DecryptMessage */
484 NULL
, /* SetContextAttributesA */
487 static const SecurityFunctionTableW schanTableW
= {
489 NULL
, /* EnumerateSecurityPackagesW */
490 schan_QueryCredentialsAttributesW
,
491 schan_AcquireCredentialsHandleW
,
492 schan_FreeCredentialsHandle
,
493 NULL
, /* Reserved2 */
494 schan_InitializeSecurityContextW
,
495 NULL
, /* AcceptSecurityContext */
496 NULL
, /* CompleteAuthToken */
497 NULL
, /* DeleteSecurityContext */
498 NULL
, /* ApplyControlToken */
499 NULL
, /* QueryContextAttributesW */
500 NULL
, /* ImpersonateSecurityContext */
501 NULL
, /* RevertSecurityContext */
502 NULL
, /* MakeSignature */
503 NULL
, /* VerifySignature */
505 NULL
, /* QuerySecurityPackageInfoW */
506 NULL
, /* Reserved3 */
507 NULL
, /* Reserved4 */
508 NULL
, /* ExportSecurityContext */
509 NULL
, /* ImportSecurityContextW */
510 NULL
, /* AddCredentialsW */
511 NULL
, /* Reserved8 */
512 NULL
, /* QuerySecurityContextToken */
513 NULL
, /* EncryptMessage */
514 NULL
, /* DecryptMessage */
515 NULL
, /* SetContextAttributesW */
518 static const WCHAR schannelComment
[] = { 'S','c','h','a','n','n','e','l',' ',
519 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
520 static const WCHAR schannelDllName
[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
522 void SECUR32_initSchannelSP(void)
524 SecureProvider
*provider
;
527 libgnutls_handle
= wine_dlopen(SONAME_LIBGNUTLS
, RTLD_NOW
, NULL
, 0);
528 if (!libgnutls_handle
)
530 WARN("Failed to load libgnutls.\n");
534 #define LOAD_FUNCPTR(f) \
535 if (!(p##f = wine_dlsym(libgnutls_handle, #f, NULL, 0))) \
537 ERR("Failed to load %s\n", #f); \
538 wine_dlclose(libgnutls_handle, NULL, 0); \
539 libgnutls_handle = NULL; \
543 LOAD_FUNCPTR(gnutls_certificate_allocate_credentials
)
544 LOAD_FUNCPTR(gnutls_certificate_free_credentials
)
545 LOAD_FUNCPTR(gnutls_global_deinit
)
546 LOAD_FUNCPTR(gnutls_global_init
)
547 LOAD_FUNCPTR(gnutls_global_set_log_function
)
548 LOAD_FUNCPTR(gnutls_global_set_log_level
)
551 provider
= SECUR32_addProvider(&schanTableA
, &schanTableW
, schannelDllName
);
555 /* This is what Windows reports. This shouldn't break any applications
556 * even though the functions are missing, because the wrapper will
557 * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
559 static const long caps
=
560 SECPKG_FLAG_INTEGRITY
|
561 SECPKG_FLAG_PRIVACY
|
562 SECPKG_FLAG_CONNECTION
|
563 SECPKG_FLAG_MULTI_REQUIRED
|
564 SECPKG_FLAG_EXTENDED_ERROR
|
565 SECPKG_FLAG_IMPERSONATION
|
566 SECPKG_FLAG_ACCEPT_WIN32_NAME
|
568 static const short version
= 1;
569 static const long maxToken
= 16384;
570 SEC_WCHAR
*uniSPName
= (SEC_WCHAR
*)UNISP_NAME_W
,
571 *schannel
= (SEC_WCHAR
*)SCHANNEL_NAME_W
;
573 const SecPkgInfoW info
[] = {
574 { caps
, version
, UNISP_RPC_ID
, maxToken
, uniSPName
, uniSPName
},
575 { caps
, version
, UNISP_RPC_ID
, maxToken
, schannel
,
576 (SEC_WCHAR
*)schannelComment
},
579 SECUR32_addPackages(provider
, sizeof(info
) / sizeof(info
[0]), NULL
,
582 schan_handle_table
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 64 * sizeof(*schan_handle_table
));
583 schan_handle_table_size
= 64;
585 pgnutls_global_init();
586 if (TRACE_ON(secur32
))
588 pgnutls_global_set_log_level(4);
589 pgnutls_global_set_log_function(schan_gnutls_log
);
594 void SECUR32_deinitSchannelSP(void)
596 pgnutls_global_deinit();
597 if (libgnutls_handle
) wine_dlclose(libgnutls_handle
, NULL
, 0);
600 #else /* SONAME_LIBGNUTLS */
602 void SECUR32_initSchannelSP(void) {}
603 void SECUR32_deinitSchannelSP(void) {}
605 #endif /* SONAME_LIBGNUTLS */