Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/secur32/schannel.c | 252 ++++++++++++++++++------- dlls/secur32/schannel_gnutls.c | 323 +++++++++++++-------------------- dlls/secur32/schannel_macosx.c | 210 ++++++++++++--------- dlls/secur32/secur32.c | 3 + dlls/secur32/secur32_priv.h | 81 +++++---- 5 files changed, 477 insertions(+), 392 deletions(-)
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 1dd3a029401..5f6b96903c4 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -17,9 +17,8 @@ * * This file implements the schannel provider, or, the SSL/TLS implementations. */ -#include "config.h" -#include "wine/port.h"
+#include <assert.h> #include <stdarg.h> #include <errno.h>
@@ -28,6 +27,7 @@ #include "winbase.h" #include "winreg.h" #include "winnls.h" +#include "lmcons.h" #include "sspi.h" #include "schannel.h" #include "secur32_priv.h" @@ -37,7 +37,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(secur32);
-#if defined(SONAME_LIBGNUTLS) || defined (HAVE_SECURITY_SECURITY_H) +const struct schan_funcs *schan_funcs = NULL;
#define SCHAN_INVALID_HANDLE ~0UL
@@ -56,7 +56,7 @@ struct schan_handle
struct schan_context { - schan_imp_session session; + schan_session session; struct schan_transport transport; ULONG req_ctx_attr; const CERT_CONTEXT *cert; @@ -242,7 +242,7 @@ static void read_config(void)
RegCloseKey(protocols_key);
- config_enabled_protocols = enabled & schan_imp_enabled_protocols(); + config_enabled_protocols = enabled & schan_funcs->get_enabled_protocols(); config_default_disabled_protocols = default_disabled; config_read = TRUE;
@@ -389,6 +389,116 @@ static SECURITY_STATUS get_cert(const SCHANNEL_CRED *cred, CERT_CONTEXT const ** return status; }
+static WCHAR *get_key_container_path(const CERT_CONTEXT *ctx) +{ + static const WCHAR rsabaseW[] = + {'S','o','f','t','w','a','r','e','\','W','i','n','e','\','C','r','y','p','t','o','\','R','S','A','\',0}; + CERT_KEY_CONTEXT keyctx; + DWORD size = sizeof(keyctx), prov_size = 0; + CRYPT_KEY_PROV_INFO *prov; + WCHAR username[UNLEN + 1], *ret = NULL; + DWORD len = ARRAY_SIZE(username); + + if (CertGetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, &keyctx, &size)) + { + char *str; + if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, NULL, &size, 0)) return NULL; + if (!(str = RtlAllocateHeap(GetProcessHeap(), 0, size))) return NULL; + if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, (BYTE *)str, &size, 0)) return NULL; + + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + if (!(ret = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(rsabaseW) + len * sizeof(WCHAR)))) + { + RtlFreeHeap(GetProcessHeap(), 0, str); + return NULL; + } + strcpyW(ret, rsabaseW); + MultiByteToWideChar(CP_ACP, 0, str, -1, ret + strlenW(ret), len); + RtlFreeHeap(GetProcessHeap(), 0, str); + } + else if (CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_size)) + { + if (!(prov = RtlAllocateHeap(GetProcessHeap(), 0, prov_size))) return NULL; + if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, prov, &prov_size)) + { + RtlFreeHeap(GetProcessHeap(), 0, prov); + return NULL; + } + if (!(ret = RtlAllocateHeap(GetProcessHeap(), 0, + sizeof(rsabaseW) + strlenW(prov->pwszContainerName) * sizeof(WCHAR)))) + { + RtlFreeHeap(GetProcessHeap(), 0, prov); + return NULL; + } + strcpyW(ret, rsabaseW); + strcatW(ret, prov->pwszContainerName); + RtlFreeHeap(GetProcessHeap(), 0, prov); + } + + if (!ret && GetUserNameW(username, &len) && (ret = RtlAllocateHeap(GetProcessHeap(), 0, + sizeof(rsabaseW) + len * sizeof(WCHAR)))) + { + strcpyW(ret, rsabaseW); + strcatW(ret, username); + } + + return ret; +} + +#define MAX_LEAD_BYTES 8 +static BYTE *get_key_blob(const CERT_CONTEXT *ctx, DWORD *size) +{ + static const WCHAR keyexchangeW[] = + {'K','e','y','E','x','c','h','a','n','g','e','K','e','y','P','a','i','r',0}; + static const WCHAR signatureW[] = + {'S','i','g','n','a','t','u','r','e','K','e','y','P','a','i','r',0}; + BYTE *buf, *ret = NULL; + DATA_BLOB blob_in, blob_out; + DWORD spec = 0, type, len; + WCHAR *path; + HKEY hkey; + + if (!(path = get_key_container_path(ctx))) return NULL; + if (RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey)) + { + RtlFreeHeap(GetProcessHeap(), 0, path); + return NULL; + } + RtlFreeHeap(GetProcessHeap(), 0, path); + + if (!RegQueryValueExW(hkey, keyexchangeW, 0, &type, NULL, &len)) spec = AT_KEYEXCHANGE; + else if (!RegQueryValueExW(hkey, signatureW, 0, &type, NULL, &len)) spec = AT_SIGNATURE; + else + { + RegCloseKey(hkey); + return NULL; + } + + if (!(buf = RtlAllocateHeap(GetProcessHeap(), 0, len + MAX_LEAD_BYTES))) + { + RegCloseKey(hkey); + return NULL; + } + + if (!RegQueryValueExW(hkey, (spec == AT_KEYEXCHANGE) ? keyexchangeW : signatureW, 0, &type, buf, &len)) + { + blob_in.pbData = buf; + blob_in.cbData = len; + if (CryptUnprotectData(&blob_in, NULL, NULL, NULL, NULL, 0, &blob_out)) + { + assert(blob_in.cbData >= blob_out.cbData); + memcpy(buf, blob_out.pbData, blob_out.cbData); + LocalFree(blob_out.pbData); + *size = blob_out.cbData + MAX_LEAD_BYTES; + ret = buf; + } + } + else RtlFreeHeap(GetProcessHeap(), 0, buf); + + RegCloseKey(hkey); + return ret; +} + static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry) { @@ -397,6 +507,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan ULONG_PTR handle; SECURITY_STATUS status = SEC_E_OK; const CERT_CONTEXT *cert = NULL; + DATA_BLOB key_blob = {0};
TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
@@ -426,20 +537,17 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan return SEC_E_NO_AUTHENTICATING_AUTHORITY; }
- creds = heap_alloc(sizeof(*creds)); - if (!creds) return SEC_E_INSUFFICIENT_MEMORY; + if (!(creds = heap_alloc(sizeof(*creds)))) return SEC_E_INSUFFICIENT_MEMORY; + creds->credential_use = SECPKG_CRED_OUTBOUND; + creds->enabled_protocols = enabled_protocols; + + if (cert && !(key_blob.pbData = get_key_blob(cert, &key_blob.cbData))) goto fail; + if (!schan_funcs->allocate_certificate_credentials(creds, cert, &key_blob)) goto fail; + RtlFreeHeap(GetProcessHeap(), 0, key_blob.pbData);
handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED); if (handle == SCHAN_INVALID_HANDLE) goto fail;
- creds->credential_use = SECPKG_CRED_OUTBOUND; - if (!schan_imp_allocate_certificate_credentials(creds, cert)) - { - schan_free_handle(handle, SCHAN_HANDLE_CRED); - goto fail; - } - - creds->enabled_protocols = enabled_protocols; phCredential->dwLower = handle; phCredential->dwUpper = 0;
@@ -454,6 +562,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
fail: heap_free(creds); + RtlFreeHeap(GetProcessHeap(), 0, key_blob.pbData); return SEC_E_INTERNAL_ERROR; }
@@ -542,10 +651,8 @@ static SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle( creds = schan_free_handle(phCredential->dwLower, SCHAN_HANDLE_CRED); if (!creds) return SEC_E_INVALID_HANDLE;
- if (creds->credential_use == SECPKG_CRED_OUTBOUND) - schan_imp_free_certificate_credentials(creds); + if (creds->credential_use == SECPKG_CRED_OUTBOUND) schan_funcs->free_certificate_credentials(creds); heap_free(creds); - return SEC_E_OK; }
@@ -599,7 +706,7 @@ static void schan_resize_current_buffer(const struct schan_buffers *s, SIZE_T mi b->pvBuffer = new_data; }
-char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) +static char * CDECL schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) { SIZE_T max_count; PSecBuffer buffer; @@ -672,7 +779,7 @@ char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, * another errno-style error value on failure * */ -int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) +static int CDECL schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) { char *b; SIZE_T local_len = *buff_len; @@ -711,7 +818,7 @@ int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) * another errno-style error value on failure * */ -int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) +static int CDECL schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) { char *b; SIZE_T local_len = *buff_len; @@ -733,7 +840,7 @@ int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) return 0; }
-schan_imp_session schan_session_for_transport(struct schan_transport* t) +static schan_session CDECL schan_get_session_for_transport(struct schan_transport* t) { return t->ctx->session; } @@ -845,7 +952,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( return SEC_E_INTERNAL_ERROR; }
- if (!schan_imp_create_session(&ctx->session, cred)) + if (!schan_funcs->create_session(&ctx->session, cred)) { schan_free_handle(handle, SCHAN_HANDLE_CTX); heap_free(ctx); @@ -858,7 +965,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( ctx->header_size = HEADER_SIZE_TLS;
ctx->transport.ctx = ctx; - schan_imp_set_session_transport(ctx->session, &ctx->transport); + schan_funcs->set_session_transport(ctx->session, &ctx->transport);
if (pszTargetName && *pszTargetName) { @@ -868,7 +975,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( if (target) { WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL ); - schan_imp_set_session_target( ctx->session, target ); + schan_funcs->set_session_target( ctx->session, target ); heap_free( target ); } } @@ -876,13 +983,13 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_APPLICATION_PROTOCOLS)) != -1) { buffer = &pInput->pBuffers[idx]; - schan_imp_set_application_protocols(ctx->session, buffer->pvBuffer, buffer->cbBuffer); + schan_funcs->set_application_protocols(ctx->session, buffer->pvBuffer, buffer->cbBuffer); }
if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_DTLS_MTU)) != -1) { buffer = &pInput->pBuffers[idx]; - if (buffer->cbBuffer >= sizeof(WORD)) schan_imp_set_dtls_mtu(ctx->session, *(WORD *)buffer->pvBuffer); + if (buffer->cbBuffer >= sizeof(WORD)) schan_funcs->set_dtls_mtu(ctx->session, *(WORD *)buffer->pvBuffer); else WARN("invalid buffer size %u\n", buffer->cbBuffer); }
@@ -935,7 +1042,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( init_schan_buffers(&ctx->transport.out, pOutput, schan_init_sec_ctx_get_next_output_buffer);
/* Perform the TLS handshake */ - ret = schan_imp_handshake(ctx->session); + ret = schan_funcs->handshake(ctx->session);
out_buffers = &ctx->transport.out; if (out_buffers->current_buffer_idx != -1) @@ -1027,18 +1134,33 @@ static void *get_alg_name(ALG_ID id, BOOL wide)
static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx) { - HCERTSTORE cert_store; + HCERTSTORE store; + PCCERT_CONTEXT cert = NULL; SECURITY_STATUS status; + struct schan_cert_list list;
- if(ctx->cert) - return SEC_E_OK; - - cert_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); - if(!cert_store) + if (ctx->cert) return SEC_E_OK; + if (!(store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL))) return GetLastError();
- status = schan_imp_get_session_peer_certificate(ctx->session, cert_store, &ctx->cert); - CertCloseStore(cert_store, 0); + if ((status = schan_funcs->get_session_peer_certificate(ctx->session, &list)) == SEC_E_OK) + { + unsigned int i; + for (i = 0; i < list.count; i++) + { + if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, list.certs[i].pbData, + list.certs[i].cbData, CERT_STORE_ADD_REPLACE_EXISTING, + i ? NULL : &cert)) + { + if (i) CertFreeCertificateContext(cert); + return GetLastError(); + } + } + RtlFreeHeap(GetProcessHeap(), 0, list.certs); + } + + ctx->cert = cert; + CertCloseStore(store, 0); return status; }
@@ -1059,13 +1181,13 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( case SECPKG_ATTR_STREAM_SIZES: { SecPkgContext_ConnectionInfo info; - status = schan_imp_get_connection_info(ctx->session, &info); + status = schan_funcs->get_connection_info(ctx->session, &info); if (status == SEC_E_OK) { SecPkgContext_StreamSizes *stream_sizes = buffer; SIZE_T mac_size = info.dwHashStrength; - unsigned int block_size = schan_imp_get_session_cipher_block_size(ctx->session); - unsigned int message_size = schan_imp_get_max_message_size(ctx->session); + unsigned int block_size = schan_funcs->get_session_cipher_block_size(ctx->session); + unsigned int message_size = schan_funcs->get_max_message_size(ctx->session);
TRACE("Using header size %lu mac bytes %lu, message size %u, block size %u\n", ctx->header_size, mac_size, message_size, block_size); @@ -1083,12 +1205,12 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( case SECPKG_ATTR_KEY_INFO: { SecPkgContext_ConnectionInfo conn_info; - status = schan_imp_get_connection_info(ctx->session, &conn_info); + status = schan_funcs->get_connection_info(ctx->session, &conn_info); if (status == SEC_E_OK) { SecPkgContext_KeyInfoW *info = buffer; info->KeySize = conn_info.dwCipherStrength; - info->SignatureAlgorithm = schan_imp_get_key_signature_algorithm(ctx->session); + info->SignatureAlgorithm = schan_funcs->get_key_signature_algorithm(ctx->session); info->EncryptAlgorithm = conn_info.aiCipher; info->sSignatureAlgorithmName = get_alg_name(info->SignatureAlgorithm, TRUE); info->sEncryptAlgorithmName = get_alg_name(info->EncryptAlgorithm, TRUE); @@ -1109,7 +1231,7 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( case SECPKG_ATTR_CONNECTION_INFO: { SecPkgContext_ConnectionInfo *info = buffer; - return schan_imp_get_connection_info(ctx->session, info); + return schan_funcs->get_connection_info(ctx->session, info); } case SECPKG_ATTR_ENDPOINT_BINDINGS: { @@ -1154,12 +1276,12 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW( case SECPKG_ATTR_UNIQUE_BINDINGS: { SecPkgContext_Bindings *bindings = buffer; - return schan_imp_get_unique_channel_binding(ctx->session, bindings); + return schan_funcs->get_unique_channel_binding(ctx->session, bindings); } case SECPKG_ATTR_APPLICATION_PROTOCOL: { SecPkgContext_ApplicationProtocol *protocol = buffer; - return schan_imp_get_application_protocol(ctx->session, protocol); + return schan_funcs->get_application_protocol(ctx->session, protocol); }
default: @@ -1289,7 +1411,7 @@ static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle init_schan_buffers(&ctx->transport.out, message, schan_encrypt_message_get_next_buffer_token);
length = data_size; - status = schan_imp_send(ctx->session, data, &length); + status = schan_funcs->send(ctx->session, data, &length);
TRACE("Sent %ld bytes.\n", length);
@@ -1422,7 +1544,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle while (received < data_size) { SIZE_T length = data_size - received; - status = schan_imp_recv(ctx->session, data + received, &length); + status = schan_funcs->recv(ctx->session, data + received, &length);
if (status == SEC_I_RENEGOTIATE) break; @@ -1478,11 +1600,9 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context ctx = schan_free_handle(context_handle->dwLower, SCHAN_HANDLE_CTX); if (!ctx) return SEC_E_INVALID_HANDLE;
- if (ctx->cert) - CertFreeCertificateContext(ctx->cert); - schan_imp_dispose_session(ctx->session); + if (ctx->cert) CertFreeCertificateContext(ctx->cert); + schan_funcs->dispose_session(ctx->session); heap_free(ctx); - return SEC_E_OK; }
@@ -1552,6 +1672,14 @@ static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ', 'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 }; static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
+const struct schan_callbacks schan_callbacks = +{ + schan_get_buffer, + schan_get_session_for_transport, + schan_pull, + schan_push, +}; + void SECUR32_initSchannelSP(void) { /* This is what Windows reports. This shouldn't break any applications @@ -1578,8 +1706,11 @@ void SECUR32_initSchannelSP(void) }; SecureProvider *provider;
- if (!schan_imp_init()) + if (!schan_funcs && __wine_init_unix_lib(hsecur32, DLL_PROCESS_ATTACH, &schan_callbacks, &schan_funcs)) + { + ERR( "no schannel support, expect problems\n" ); return; + }
schan_handle_table = heap_alloc(64 * sizeof(*schan_handle_table)); if (!schan_handle_table) @@ -1597,13 +1728,11 @@ void SECUR32_initSchannelSP(void) }
SECUR32_addPackages(provider, ARRAY_SIZE(info), NULL, info); - return;
fail: heap_free(schan_handle_table); schan_handle_table = NULL; - schan_imp_deinit(); return; }
@@ -1620,7 +1749,7 @@ void SECUR32_deinitSchannelSP(void) if (schan_handle_table[i].type == SCHAN_HANDLE_CTX) { struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX); - schan_imp_dispose_session(ctx->session); + schan_funcs->dispose_session(ctx->session); heap_free(ctx); } } @@ -1631,21 +1760,12 @@ void SECUR32_deinitSchannelSP(void) { struct schan_credentials *cred; cred = schan_free_handle(i, SCHAN_HANDLE_CRED); - schan_imp_free_certificate_credentials(cred); + schan_funcs->free_certificate_credentials(cred); heap_free(cred); } } heap_free(schan_handle_table); - schan_imp_deinit(); -} - -#else /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H */
-void SECUR32_initSchannelSP(void) -{ - ERR("TLS library not found, SSL connections will fail\n"); + __wine_init_unix_lib(hsecur32, DLL_PROCESS_DETACH, NULL, NULL); + schan_funcs = NULL; } - -void SECUR32_deinitSchannelSP(void) {} - -#endif /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H */ diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c index 785430ddf58..76ab230137d 100644 --- a/dlls/secur32/schannel_gnutls.c +++ b/dlls/secur32/schannel_gnutls.c @@ -19,23 +19,27 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#if 0 +#pragma makedep unix +#endif + #include "config.h" #include "wine/port.h"
#include <stdarg.h> #include <stdio.h> -#include <assert.h> #ifdef SONAME_LIBGNUTLS #include <gnutls/gnutls.h> #include <gnutls/crypto.h> #include <gnutls/abstract.h> #endif
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "sspi.h" #include "schannel.h" -#include "lmcons.h" #include "winreg.h" #include "secur32_priv.h"
@@ -47,6 +51,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(secur32); WINE_DECLARE_DEBUG_CHANNEL(winediag);
+static const struct schan_callbacks *callbacks; + /* Not present in gnutls version < 2.9.10. */ static int (*pgnutls_cipher_get_block_size)(gnutls_cipher_algorithm_t);
@@ -192,13 +198,12 @@ static void compat_gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mt FIXME("\n"); }
-static ssize_t schan_pull_adapter(gnutls_transport_ptr_t transport, - void *buff, size_t buff_len) +static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t buff_len) { struct schan_transport *t = (struct schan_transport*)transport; - gnutls_session_t s = (gnutls_session_t)schan_session_for_transport(t); + gnutls_session_t s = (gnutls_session_t)callbacks->get_session_for_transport(t);
- int ret = schan_pull(transport, buff, &buff_len); + int ret = callbacks->pull(transport, buff, &buff_len); if (ret) { pgnutls_transport_set_errno(s, ret); @@ -208,13 +213,12 @@ static ssize_t schan_pull_adapter(gnutls_transport_ptr_t transport, return buff_len; }
-static ssize_t schan_push_adapter(gnutls_transport_ptr_t transport, - const void *buff, size_t buff_len) +static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff, size_t buff_len) { struct schan_transport *t = (struct schan_transport*)transport; - gnutls_session_t s = (gnutls_session_t)schan_session_for_transport(t); + gnutls_session_t s = (gnutls_session_t)callbacks->get_session_for_transport(t);
- int ret = schan_push(transport, buff, &buff_len); + int ret = callbacks->push(transport, buff, &buff_len); if (ret) { pgnutls_transport_set_errno(s, ret); @@ -270,21 +274,21 @@ static void check_supported_protocols(void) pgnutls_deinit(session); }
-DWORD schan_imp_enabled_protocols(void) +static DWORD CDECL schan_get_enabled_protocols(void) { return supported_protocols; }
-static int schan_pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout) +static int pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout) { struct schan_transport *t = (struct schan_transport *)transport; SIZE_T count = 0;
- if (schan_get_buffer(t, &t->in, &count)) return 1; + if (callbacks->get_buffer(t, &t->in, &count)) return 1; return 0; }
-BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) +static BOOL CDECL schan_create_session(schan_session *session, schan_credentials *cred) { gnutls_session_t *s = (gnutls_session_t*)session; char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p; @@ -347,34 +351,32 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre return FALSE; }
- pgnutls_transport_set_pull_function(*s, schan_pull_adapter); - if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(*s, schan_pull_timeout); - pgnutls_transport_set_push_function(*s, schan_push_adapter); + pgnutls_transport_set_pull_function(*s, pull_adapter); + if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(*s, pull_timeout); + pgnutls_transport_set_push_function(*s, push_adapter);
return TRUE; }
-void schan_imp_dispose_session(schan_imp_session session) +static void CDECL schan_dispose_session(schan_session session) { gnutls_session_t s = (gnutls_session_t)session; pgnutls_deinit(s); }
-void schan_imp_set_session_transport(schan_imp_session session, - struct schan_transport *t) +static void CDECL schan_set_session_transport(schan_session session, struct schan_transport *t) { gnutls_session_t s = (gnutls_session_t)session; pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)t); }
-void schan_imp_set_session_target(schan_imp_session session, const char *target) +static void CDECL schan_set_session_target(schan_session session, const char *target) { gnutls_session_t s = (gnutls_session_t)session; - pgnutls_server_name_set( s, GNUTLS_NAME_DNS, target, strlen(target) ); }
-SECURITY_STATUS schan_imp_handshake(schan_imp_session session) +static SECURITY_STATUS CDECL schan_handshake(schan_session session) { gnutls_session_t s = (gnutls_session_t)session; int err; @@ -422,7 +424,7 @@ SECURITY_STATUS schan_imp_handshake(schan_imp_session session) return SEC_E_OK; }
-static DWORD schannel_get_protocol(gnutls_protocol_t proto) +static DWORD get_protocol(gnutls_protocol_t proto) { /* FIXME: currently schannel only implements client connections, but * there's no reason it couldn't be used for servers as well. The @@ -442,7 +444,7 @@ static DWORD schannel_get_protocol(gnutls_protocol_t proto) } }
-static ALG_ID schannel_get_cipher_algid(gnutls_cipher_algorithm_t cipher) +static ALG_ID get_cipher_algid(gnutls_cipher_algorithm_t cipher) { switch (cipher) { @@ -464,7 +466,7 @@ static ALG_ID schannel_get_cipher_algid(gnutls_cipher_algorithm_t cipher) } }
-static ALG_ID schannel_get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_algorithm_t cipher) +static ALG_ID get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_algorithm_t cipher) { switch (mac) { @@ -493,7 +495,7 @@ static ALG_ID schannel_get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_a } }
-static ALG_ID schannel_get_kx_algid(int kx) +static ALG_ID get_kx_algid(int kx) { switch (kx) { @@ -513,19 +515,18 @@ static ALG_ID schannel_get_kx_algid(int kx) } }
-unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) +static unsigned int CDECL schan_get_session_cipher_block_size(schan_session session) { gnutls_session_t s = (gnutls_session_t)session; return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s)); }
-unsigned int schan_imp_get_max_message_size(schan_imp_session session) +static unsigned int CDECL schan_get_max_message_size(schan_session session) { return pgnutls_record_get_max_size((gnutls_session_t)session); }
-SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, - SecPkgContext_ConnectionInfo *info) +static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, SecPkgContext_ConnectionInfo *info) { gnutls_session_t s = (gnutls_session_t)session; gnutls_protocol_t proto = pgnutls_protocol_get_version(s); @@ -533,19 +534,18 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, gnutls_mac_algorithm_t mac = pgnutls_mac_get(s); gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
- info->dwProtocol = schannel_get_protocol(proto); - info->aiCipher = schannel_get_cipher_algid(alg); + info->dwProtocol = get_protocol(proto); + info->aiCipher = get_cipher_algid(alg); info->dwCipherStrength = pgnutls_cipher_get_key_size(alg) * 8; - info->aiHash = schannel_get_mac_algid(mac, alg); + info->aiHash = get_mac_algid(mac, alg); info->dwHashStrength = pgnutls_mac_get_key_size(mac) * 8; - info->aiExch = schannel_get_kx_algid(kx); + info->aiExch = get_kx_algid(kx); /* FIXME: info->dwExchStrength? */ info->dwExchStrength = 0; return SEC_E_OK; }
-SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session, - SecPkgContext_Bindings *bindings) +static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session session, SecPkgContext_Bindings *bindings) { static const char prefix[] = "tls-unique:"; gnutls_datum_t datum; @@ -562,7 +562,7 @@ SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session, }
bindings->BindingsLength = sizeof(SEC_CHANNEL_BINDINGS) + sizeof(prefix)-1 + datum.size; - bindings->Bindings = heap_alloc_zero(bindings->BindingsLength); + bindings->Bindings = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, bindings->BindingsLength); if (!bindings->Bindings) ret = SEC_E_INSUFFICIENT_MEMORY; else @@ -579,7 +579,7 @@ SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session, return ret; }
-ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) +static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session) { gnutls_session_t s = (gnutls_session_t)session; gnutls_kx_algorithm_t kx = pgnutls_kx_get(s); @@ -600,35 +600,32 @@ ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) } }
-SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store, - PCCERT_CONTEXT *ret) +static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, struct schan_cert_list *list) { gnutls_session_t s = (gnutls_session_t)session; - PCCERT_CONTEXT cert = NULL; const gnutls_datum_t *datum; - unsigned list_size, i; - BOOL res; + unsigned int i, size; + BYTE *ptr;
- datum = pgnutls_certificate_get_peers(s, &list_size); - if(!datum) - return SEC_E_INTERNAL_ERROR; + if (!(datum = pgnutls_certificate_get_peers(s, &list->count))) return SEC_E_INTERNAL_ERROR;
- for(i = 0; i < list_size; i++) { - res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, datum[i].data, datum[i].size, - CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert); - if(!res) { - if(i) - CertFreeCertificateContext(cert); - return GetLastError(); - } + size = list->count * sizeof(list->certs[0]); + for (i = 0; i < list->count; i++) size += datum[i].size; + if (!(list->certs = RtlAllocateHeap(GetProcessHeap(), 0, size))) return SEC_E_INSUFFICIENT_MEMORY; + + ptr = (BYTE *)&list->certs[list->count]; + for (i = 0; i < list->count; i++) + { + list->certs[i].cbData = datum[i].size; + list->certs[i].pbData = ptr; + memcpy(list->certs[i].pbData, datum[i].data, datum[i].size); + ptr += datum[i].size; }
- *ret = cert; return SEC_E_OK; }
-SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, - SIZE_T *length) +static SECURITY_STATUS CDECL schan_send(schan_session session, const void *buffer, SIZE_T *length) { gnutls_session_t s = (gnutls_session_t)session; SSIZE_T ret, total = 0; @@ -647,7 +644,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s); SIZE_T count = 0;
- if (schan_get_buffer(t, &t->out, &count)) continue; + if (callbacks->get_buffer(t, &t->out, &count)) continue; return SEC_I_CONTINUE_NEEDED; } else @@ -658,8 +655,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, } }
-SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, - SIZE_T *length) +static SECURITY_STATUS CDECL schan_recv(schan_session session, void *buffer, SIZE_T *length) { gnutls_session_t s = (gnutls_session_t)session; ssize_t ret; @@ -674,7 +670,7 @@ again: struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s); SIZE_T count = 0;
- if (schan_get_buffer(t, &t->in, &count)) + if (callbacks->get_buffer(t, &t->in, &count)) goto again;
return SEC_I_CONTINUE_NEEDED; @@ -715,7 +711,7 @@ static unsigned int parse_alpn_protocol_list(unsigned char *buffer, unsigned int return count; }
-void schan_imp_set_application_protocols(schan_imp_session session, unsigned char *buffer, unsigned int buflen) +static void CDECL schan_set_application_protocols(schan_session session, unsigned char *buffer, unsigned int buflen) { gnutls_session_t s = (gnutls_session_t)session; unsigned int extension_len, extension, count = 0, offset = 0; @@ -742,7 +738,7 @@ void schan_imp_set_application_protocols(schan_imp_session session, unsigned cha
if (offset + list_len > buflen) return; count = parse_alpn_protocol_list(&buffer[offset], list_len, NULL); - if (!count || !(protocols = heap_alloc(count * sizeof(*protocols)))) return; + if (!count || !(protocols = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(*protocols)))) return;
parse_alpn_protocol_list(&buffer[offset], list_len, protocols); if ((ret = pgnutls_alpn_set_protocols(s, protocols, count, GNUTLS_ALPN_SERVER_PRECEDENCE) < 0)) @@ -750,11 +746,11 @@ void schan_imp_set_application_protocols(schan_imp_session session, unsigned cha pgnutls_perror(ret); }
- heap_free(protocols); + RtlFreeHeap(GetProcessHeap(), 0, protocols); }
-SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session, - SecPkgContext_ApplicationProtocol *protocol) +static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session session, + SecPkgContext_ApplicationProtocol *protocol) { gnutls_session_t s = (gnutls_session_t)session; gnutls_datum_t selected; @@ -768,12 +764,12 @@ SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session, protocol->ProtoNegoExt = SecApplicationProtocolNegotiationExt_ALPN; protocol->ProtocolIdSize = selected.size; memcpy(protocol->ProtocolId, selected.data, selected.size); - TRACE("returning %s\n", debugstr_an((const char *)selected.data, selected.size)); + TRACE("returning %s\n", wine_dbgstr_an((const char *)selected.data, selected.size)); } return SEC_E_OK; }
-SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int mtu) +static SECURITY_STATUS CDECL schan_set_dtls_mtu(schan_session session, unsigned int mtu) { gnutls_session_t s = (gnutls_session_t)session;
@@ -782,114 +778,6 @@ SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int m return SEC_E_OK; }
-static WCHAR *get_key_container_path(const CERT_CONTEXT *ctx) -{ - static const WCHAR rsabaseW[] = - {'S','o','f','t','w','a','r','e','\','W','i','n','e','\','C','r','y','p','t','o','\','R','S','A','\',0}; - CERT_KEY_CONTEXT keyctx; - DWORD size = sizeof(keyctx), prov_size = 0; - CRYPT_KEY_PROV_INFO *prov; - WCHAR username[UNLEN + 1], *ret = NULL; - DWORD len = ARRAY_SIZE(username); - - if (CertGetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, &keyctx, &size)) - { - char *str; - if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, NULL, &size, 0)) return NULL; - if (!(str = heap_alloc(size))) return NULL; - if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, (BYTE *)str, &size, 0)) return NULL; - - len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); - if (!(ret = heap_alloc(sizeof(rsabaseW) + len * sizeof(WCHAR)))) - { - heap_free(str); - return NULL; - } - strcpyW(ret, rsabaseW); - MultiByteToWideChar(CP_ACP, 0, str, -1, ret + strlenW(ret), len); - heap_free(str); - } - else if (CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_size)) - { - if (!(prov = heap_alloc(prov_size))) return NULL; - if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, prov, &prov_size)) - { - heap_free(prov); - return NULL; - } - if (!(ret = heap_alloc(sizeof(rsabaseW) + strlenW(prov->pwszContainerName) * sizeof(WCHAR)))) - { - heap_free(prov); - return NULL; - } - strcpyW(ret, rsabaseW); - strcatW(ret, prov->pwszContainerName); - heap_free(prov); - } - - if (!ret && GetUserNameW(username, &len) && (ret = heap_alloc(sizeof(rsabaseW) + len * sizeof(WCHAR)))) - { - strcpyW(ret, rsabaseW); - strcatW(ret, username); - } - - return ret; -} - -#define MAX_LEAD_BYTES 8 -static BYTE *get_key_blob(const CERT_CONTEXT *ctx, ULONG *size) -{ - static const WCHAR keyexchangeW[] = - {'K','e','y','E','x','c','h','a','n','g','e','K','e','y','P','a','i','r',0}; - static const WCHAR signatureW[] = - {'S','i','g','n','a','t','u','r','e','K','e','y','P','a','i','r',0}; - BYTE *buf, *ret = NULL; - DATA_BLOB blob_in, blob_out; - DWORD spec = 0, type, len; - WCHAR *path; - HKEY hkey; - - if (!(path = get_key_container_path(ctx))) return NULL; - if (RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey)) - { - heap_free(path); - return NULL; - } - heap_free(path); - - if (!RegQueryValueExW(hkey, keyexchangeW, 0, &type, NULL, &len)) spec = AT_KEYEXCHANGE; - else if (!RegQueryValueExW(hkey, signatureW, 0, &type, NULL, &len)) spec = AT_SIGNATURE; - else - { - RegCloseKey(hkey); - return NULL; - } - - if (!(buf = heap_alloc(len + MAX_LEAD_BYTES))) - { - RegCloseKey(hkey); - return NULL; - } - - if (!RegQueryValueExW(hkey, (spec == AT_KEYEXCHANGE) ? keyexchangeW : signatureW, 0, &type, buf, &len)) - { - blob_in.pbData = buf; - blob_in.cbData = len; - if (CryptUnprotectData(&blob_in, NULL, NULL, NULL, NULL, 0, &blob_out)) - { - assert(blob_in.cbData >= blob_out.cbData); - memcpy(buf, blob_out.pbData, blob_out.cbData); - LocalFree(blob_out.pbData); - *size = blob_out.cbData + MAX_LEAD_BYTES; - ret = buf; - } - } - else heap_free(buf); - - RegCloseKey(hkey); - return ret; -} - static inline void reverse_bytes(BYTE *buf, ULONG len) { BYTE tmp; @@ -917,20 +805,19 @@ static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *b return comp->size; }
-static gnutls_x509_privkey_t get_x509_key(const CERT_CONTEXT *ctx) +static gnutls_x509_privkey_t get_x509_key(const DATA_BLOB *key_blob) { gnutls_privkey_t key = NULL; gnutls_x509_privkey_t x509key = NULL; gnutls_datum_t m, e, d, p, q, u, e1, e2; - BYTE *ptr, *buffer; + BYTE *ptr; RSAPUBKEY *rsakey; - DWORD size; + DWORD size = key_blob->cbData; int ret;
- if (!(buffer = get_key_blob(ctx, &size))) return NULL; - if (size < sizeof(BLOBHEADER)) goto done; + if (size < sizeof(BLOBHEADER)) return NULL;
- rsakey = (RSAPUBKEY *)(buffer + sizeof(BLOBHEADER)); + rsakey = (RSAPUBKEY *)(key_blob->pbData + sizeof(BLOBHEADER)); TRACE("RSA key bitlen %u pubexp %u\n", rsakey->bitlen, rsakey->pubexp);
size -= sizeof(BLOBHEADER) + FIELD_OFFSET(RSAPUBKEY, pubexp); @@ -948,23 +835,17 @@ static gnutls_x509_privkey_t get_x509_key(const CERT_CONTEXT *ctx) if ((ret = pgnutls_privkey_init(&key)) < 0) { pgnutls_perror(ret); - goto done; - } - - if ((ret = pgnutls_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u, &e1, &e2)) < 0) - { - pgnutls_perror(ret); - goto done; + return NULL; }
- if ((ret = pgnutls_privkey_export_x509(key, &x509key)) < 0) + if (((ret = pgnutls_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u, &e1, &e2)) < 0) || + (ret = pgnutls_privkey_export_x509(key, &x509key)) < 0) { pgnutls_perror(ret); + pgnutls_privkey_deinit(key); + return NULL; }
-done: - heap_free(buffer); - pgnutls_privkey_deinit(key); return x509key; }
@@ -999,7 +880,8 @@ static gnutls_x509_crt_t get_x509_crt(const CERT_CONTEXT *ctx) return crt; }
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx) +static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx, + const DATA_BLOB *key_blob ) { gnutls_certificate_credentials_t creds; gnutls_x509_crt_t crt; @@ -1025,7 +907,7 @@ BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT return FALSE; }
- if (!(key = get_x509_key(ctx))) + if (!(key = get_x509_key(key_blob))) { pgnutls_x509_crt_deinit(crt); pgnutls_certificate_free_credentials(creds); @@ -1046,17 +928,17 @@ BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT return TRUE; }
-void schan_imp_free_certificate_credentials(schan_credentials *c) +static void CDECL schan_free_certificate_credentials(schan_credentials *c) { pgnutls_certificate_free_credentials(c->credentials); }
-static void schan_gnutls_log(int level, const char *msg) +static void gnutls_log(int level, const char *msg) { TRACE("<%d> %s", level, msg); }
-BOOL schan_imp_init(void) +static BOOL gnutls_initialize(void) { const char *env_str; int ret; @@ -1171,7 +1053,7 @@ BOOL schan_imp_init(void) if (TRACE_ON(secur32)) { pgnutls_global_set_log_level(4); - pgnutls_global_set_log_function(schan_gnutls_log); + pgnutls_global_set_log_function(gnutls_log); }
check_supported_protocols(); @@ -1183,11 +1065,50 @@ fail: return FALSE; }
-void schan_imp_deinit(void) +static void gnutls_uninitialize(void) { pgnutls_global_deinit(); dlclose(libgnutls_handle); libgnutls_handle = NULL; }
+static const struct schan_funcs funcs = +{ + schan_allocate_certificate_credentials, + schan_create_session, + schan_dispose_session, + schan_free_certificate_credentials, + schan_get_application_protocol, + schan_get_connection_info, + schan_get_enabled_protocols, + schan_get_key_signature_algorithm, + schan_get_max_message_size, + schan_get_session_cipher_block_size, + schan_get_session_peer_certificate, + schan_get_unique_channel_binding, + schan_handshake, + schan_recv, + schan_send, + schan_set_application_protocols, + schan_set_dtls_mtu, + schan_set_session_target, + schan_set_session_transport, +}; + +NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out ) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + if (!gnutls_initialize()) return STATUS_DLL_NOT_FOUND; + callbacks = ptr_in; + *(const struct schan_funcs **)ptr_out = &funcs; + break; + case DLL_PROCESS_DETACH: + if (libgnutls_handle) gnutls_uninitialize(); + break; + } + return STATUS_SUCCESS; +} + #endif /* SONAME_LIBGNUTLS && !HAVE_SECURITY_SECURITY_H */ diff --git a/dlls/secur32/schannel_macosx.c b/dlls/secur32/schannel_macosx.c index 841f928eef3..daf9d835835 100644 --- a/dlls/secur32/schannel_macosx.c +++ b/dlls/secur32/schannel_macosx.c @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#if 0 +#pragma makedep unix +#endif + #include "config.h" #include "wine/port.h"
@@ -33,10 +37,13 @@ #undef LoadResource #endif
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "sspi.h" #include "schannel.h" +#include "winternl.h" #include "secur32_priv.h" #include "wine/debug.h"
@@ -44,6 +51,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+static const struct schan_callbacks *callbacks; + #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 /* Defined in <Security/CipherSuite.h> in the 10.6 SDK or later. */ enum { @@ -444,7 +453,7 @@ static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite) }
-static DWORD schan_get_session_protocol(struct mac_session* s) +static DWORD get_session_protocol(struct mac_session* s) { SSLProtocol protocol; int status; @@ -473,7 +482,7 @@ static DWORD schan_get_session_protocol(struct mac_session* s) } }
-static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c) +static ALG_ID get_cipher_algid(const struct cipher_suite* c) { TRACE("(%#x)\n", (unsigned int)c->suite);
@@ -503,7 +512,7 @@ static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c) } }
-static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c) +static unsigned int get_cipher_key_size(const struct cipher_suite* c) { TRACE("(%#x)\n", (unsigned int)c->suite);
@@ -533,7 +542,7 @@ static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c) } }
-static ALG_ID schan_get_mac_algid(const struct cipher_suite* c) +static ALG_ID get_mac_algid(const struct cipher_suite* c) { TRACE("(%#x)\n", (unsigned int)c->suite);
@@ -551,7 +560,7 @@ static ALG_ID schan_get_mac_algid(const struct cipher_suite* c) } }
-static unsigned int schan_get_mac_key_size(const struct cipher_suite* c) +static unsigned int get_mac_key_size(const struct cipher_suite* c) { TRACE("(%#x)\n", (unsigned int)c->suite);
@@ -569,7 +578,7 @@ static unsigned int schan_get_mac_key_size(const struct cipher_suite* c) } }
-static ALG_ID schan_get_kx_algid(const struct cipher_suite* c) +static ALG_ID get_kx_algid(const struct cipher_suite* c) { TRACE("(%#x)\n", (unsigned int)c->suite);
@@ -608,7 +617,7 @@ static ALG_ID schan_get_kx_algid(const struct cipher_suite* c) }
-/* schan_pull_adapter +/* pull_adapter * Callback registered with SSLSetIOFuncs as the read function for a * session. Reads data from the session connection. Conforms to the * SSLReadFunc type. @@ -629,8 +638,7 @@ static ALG_ID schan_get_kx_algid(const struct cipher_suite* c) * more data to be read. * other error code for failure. */ -static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff, - SIZE_T *buff_len) +static OSStatus pull_adapter(SSLConnectionRef transport, void *buff, SIZE_T *buff_len) { struct mac_session *s = (struct mac_session*)transport; size_t requested = *buff_len; @@ -645,7 +653,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff, return noErr; }
- status = schan_pull(s->transport, buff, buff_len); + status = callbacks->pull(s->transport, buff, buff_len); if (status == 0) { if (*buff_len == 0) @@ -678,7 +686,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff, return ret; }
-/* schan_push_adapter +/* push_adapter * Callback registered with SSLSetIOFuncs as the write function for a * session. Writes data to the session connection. Conforms to the * SSLWriteFunc type. @@ -695,8 +703,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff, * caller should try again. * other error code for failure. */ -static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff, - SIZE_T *buff_len) +static OSStatus push_adapter(SSLConnectionRef transport, const void *buff, SIZE_T *buff_len) { struct mac_session *s = (struct mac_session*)transport; int status; @@ -710,7 +717,7 @@ static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff, return noErr; }
- status = schan_push(s->transport, buff, buff_len); + status = callbacks->push(s->transport, buff, buff_len); if (status == 0) { TRACE("Pushed %lu bytes\n", *buff_len); @@ -743,12 +750,12 @@ static const struct {
static DWORD supported_protocols;
-DWORD schan_imp_enabled_protocols(void) +static DWORD CDECL schan_get_enabled_protocols(void) { return supported_protocols; }
-BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) +static BOOL CDECL schan_create_session(schan_session *session, schan_credentials *cred) { struct mac_session *s; unsigned i; @@ -756,9 +763,7 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
TRACE("(%p)\n", session);
- s = heap_alloc(sizeof(*s)); - if (!s) - return FALSE; + if (!(s = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*s)))) return FALSE;
pthread_mutex_init(&s->mutex, NULL);
@@ -796,7 +801,7 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre } }
- status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter); + status = SSLSetIOFuncs(s->context, pull_adapter, push_adapter); if (status != noErr) { ERR("Failed to set session I/O funcs: %d\n", status); @@ -807,15 +812,15 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
TRACE(" -> %p/%p\n", s, s->context);
- *session = (schan_imp_session)s; + *session = (schan_session)s; return TRUE;
fail: - heap_free(s); + RtlFreeHeap(GetProcessHeap(), 0, s); return FALSE; }
-void schan_imp_dispose_session(schan_imp_session session) +static void CDECL schan_dispose_session(schan_session session) { struct mac_session *s = (struct mac_session*)session; int status; @@ -826,11 +831,10 @@ void schan_imp_dispose_session(schan_imp_session session) if (status != noErr) ERR("Failed to dispose of session context: %d\n", status); pthread_mutex_destroy(&s->mutex); - heap_free(s); + RtlFreeHeap(GetProcessHeap(), 0, s); }
-void schan_imp_set_session_transport(schan_imp_session session, - struct schan_transport *t) +static void CDECL schan_set_session_transport(schan_session session, struct schan_transport *t) { struct mac_session *s = (struct mac_session*)session;
@@ -839,7 +843,7 @@ void schan_imp_set_session_transport(schan_imp_session session, s->transport = t; }
-void schan_imp_set_session_target(schan_imp_session session, const char *target) +static void CDECL schan_set_session_target(schan_session session, const char *target) { struct mac_session *s = (struct mac_session*)session;
@@ -848,7 +852,7 @@ void schan_imp_set_session_target(schan_imp_session session, const char *target) SSLSetPeerDomainName( s->context, target, strlen(target) ); }
-SECURITY_STATUS schan_imp_handshake(schan_imp_session session) +static SECURITY_STATUS CDECL schan_handshake(schan_session session) { struct mac_session *s = (struct mac_session*)session; int status; @@ -885,7 +889,7 @@ SECURITY_STATUS schan_imp_handshake(schan_imp_session session) return SEC_E_OK; }
-unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) +static unsigned int CDECL schan_get_session_cipher_block_size(schan_session session) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; @@ -934,13 +938,13 @@ unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) } }
-unsigned int schan_imp_get_max_message_size(schan_imp_session session) +static unsigned int CDECL schan_get_max_message_size(schan_session session) { FIXME("Returning 1 << 14.\n"); return 1 << 14; }
-ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) +static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; @@ -1002,8 +1006,7 @@ ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) } }
-SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, - SecPkgContext_ConnectionInfo *info) +static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, SecPkgContext_ConnectionInfo *info) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; @@ -1026,46 +1029,44 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, return SEC_E_INTERNAL_ERROR; }
- info->dwProtocol = schan_get_session_protocol(s); - info->aiCipher = schan_get_cipher_algid(c); - info->dwCipherStrength = schan_get_cipher_key_size(c); - info->aiHash = schan_get_mac_algid(c); - info->dwHashStrength = schan_get_mac_key_size(c); - info->aiExch = schan_get_kx_algid(c); + info->dwProtocol = get_session_protocol(s); + info->aiCipher = get_cipher_algid(c); + info->dwCipherStrength = get_cipher_key_size(c); + info->aiHash = get_mac_algid(c); + info->dwHashStrength = get_mac_key_size(c); + info->aiExch = get_kx_algid(c); /* FIXME: info->dwExchStrength? */ info->dwExchStrength = 0;
return SEC_E_OK; }
-SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session, - SecPkgContext_Bindings *bindings) +static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session session, SecPkgContext_Bindings *bindings) { FIXME("SECPKG_ATTR_UNIQUE_BINDINGS is unsupported on MacOS\n"); return SEC_E_UNSUPPORTED_FUNCTION; }
#ifndef HAVE_SSLCOPYPEERCERTIFICATES -static void schan_imp_cf_release(const void *arg, void *ctx) +static void cf_release(const void *arg, void *ctx) { CFRelease(arg); } #endif
-SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store, - PCCERT_CONTEXT *ret_cert) +static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, struct schan_cert_list *list) { - struct mac_session* s = (struct mac_session*)session; + struct mac_session *s = (struct mac_session *)session; SECURITY_STATUS ret = SEC_E_OK; - PCCERT_CONTEXT cert = NULL; - SecCertificateRef mac_cert; + SecCertificateRef cert; CFArrayRef cert_array; int status; - CFIndex cnt, i; + unsigned int size; + CFIndex i; CFDataRef data; - BOOL res; + BYTE *ptr;
- TRACE("(%p/%p, %p)\n", s, s->context, cert); + TRACE("(%p/%p, %p)\n", s, s->context, list);
#ifdef HAVE_SSLCOPYPEERCERTIFICATES status = SSLCopyPeerCertificates(s->context, &cert_array); @@ -1078,45 +1079,55 @@ SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session return SEC_E_INTERNAL_ERROR; }
- cnt = CFArrayGetCount(cert_array); - for (i=0; i < cnt; i++) { - if (!(mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) || - (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) != noErr)) + list->count = CFArrayGetCount(cert_array); + size = list->count * sizeof(list->certs[0]); + + for (i = 0; i < list->count; i++) + { + if (!(cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) || + (SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &data) != noErr)) { WARN("Couldn't extract certificate data\n"); ret = SEC_E_INTERNAL_ERROR; - break; + goto done; } - - res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(data), CFDataGetLength(data), - CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert); + size += CFDataGetLength(data); CFRelease(data); - if (!res) + } + + if (!(list->certs = RtlAllocateHeap(GetProcessHeap(), 0, size))) + { + ret = SEC_E_INSUFFICIENT_MEMORY; + goto done; + } + + ptr = (BYTE *)&list->certs[list->count]; + for (i = 0; i < list->count; i++) + { + if (!(cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) || + (SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &data) != noErr)) { - ret = GetLastError(); - WARN("CertAddEncodedCertificateToStore failed: %x\n", ret); - break; + WARN("Couldn't extract certificate data\n"); + ret = SEC_E_INTERNAL_ERROR; + goto done; } + list->certs[i].cbData = CFDataGetLength(data); + list->certs[i].pbData = ptr; + memcpy(list->certs[i].pbData, CFDataGetBytePtr(data), CFDataGetLength(data)); + ptr += CFDataGetLength(data); + CFRelease(data); }
+done: #ifndef HAVE_SSLCOPYPEERCERTIFICATES /* This is why SSLGetPeerCertificates was deprecated */ - CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)), - schan_imp_cf_release, NULL); + CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)), cf_release, NULL); #endif CFRelease(cert_array); - if (ret != SEC_E_OK) { - if(cert) - CertFreeCertificateContext(cert); - return ret; - } - - *ret_cert = cert; - return SEC_E_OK; + return ret; }
-SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, - SIZE_T *length) +static SECURITY_STATUS CDECL schan_send(schan_session session, const void *buffer, SIZE_T *length) { struct mac_session* s = (struct mac_session*)session; int status; @@ -1152,8 +1163,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, return SEC_E_OK; }
-SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, - SIZE_T *length) +static SECURITY_STATUS CDECL schan_recv(schan_session session, void *buffer, SIZE_T *length) { struct mac_session* s = (struct mac_session*)session; int status; @@ -1189,36 +1199,37 @@ SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, return SEC_E_OK; }
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *cert) +static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *cert, + const DATA_BLOB *key_blob) { if (cert) FIXME("no support for certificate credentials on this platform\n"); c->credentials = NULL; return TRUE; }
-void schan_imp_free_certificate_credentials(schan_credentials *c) +static void CDECL schan_free_certificate_credentials(schan_credentials *c) { }
-void schan_imp_set_application_protocols(schan_imp_session session, unsigned char *buffer, unsigned int buflen) +static void CDECL schan_set_application_protocols(schan_session session, unsigned char *buffer, unsigned int buflen) { FIXME("no support for application protocols on this platform\n"); }
-SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session, - SecPkgContext_ApplicationProtocol *protocol) +static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session session, + SecPkgContext_ApplicationProtocol *protocol) { FIXME("no support for application protocols on this platform\n"); return SEC_E_UNSUPPORTED_FUNCTION; }
-SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int mtu) +static SECURITY_STATUS CDECL schan_set_dtls_mtu(schan_session session, unsigned int mtu) { FIXME("no support for setting dtls mtu on this platform\n"); return SEC_E_UNSUPPORTED_FUNCTION; }
-BOOL schan_imp_init(void) +static void ssl_init(void) { TRACE("()\n");
@@ -1245,13 +1256,38 @@ BOOL schan_imp_init(void) } } #endif - - return TRUE; }
-void schan_imp_deinit(void) +static const struct schan_funcs funcs = { - TRACE("()\n"); + schan_allocate_certificate_credentials, + schan_create_session, + schan_dispose_session, + schan_free_certificate_credentials, + schan_get_application_protocol, + schan_get_connection_info, + schan_get_enabled_protocols, + schan_get_key_signature_algorithm, + schan_get_max_message_size, + schan_get_session_cipher_block_size, + schan_get_session_peer_certificate, + schan_get_unique_channel_binding, + schan_handshake, + schan_recv, + schan_send, + schan_set_application_protocols, + schan_set_dtls_mtu, + schan_set_session_target, + schan_set_session_transport, +}; + +NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out ) +{ + if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS; + ssl_init(); + callbacks = ptr_in; + *(const struct schan_funcs **)ptr_out = &funcs; + return STATUS_SUCCESS; }
#endif /* HAVE_SECURITY_SECURITY_H */ diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c index 4382ec55174..04cb52dbec9 100644 --- a/dlls/secur32/secur32.c +++ b/dlls/secur32/secur32.c @@ -40,6 +40,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(secur32);
+HINSTANCE hsecur32; + /** * Type definitions */ @@ -1246,6 +1248,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) switch (reason) { case DLL_PROCESS_ATTACH: + hsecur32 = hinstDLL; DisableThreadLibraryCalls(hinstDLL); SECUR32_initializeProviders(); break; diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h index 5571ac290e1..9d191fc4872 100644 --- a/dlls/secur32/secur32_priv.h +++ b/dlls/secur32/secur32_priv.h @@ -27,6 +27,8 @@ #include "wine/list.h" #include "schannel.h"
+extern HINSTANCE hsecur32 DECLSPEC_HIDDEN; + typedef struct _SecureProvider { struct list entry; @@ -83,7 +85,7 @@ void load_auth_packages(void) DECLSPEC_HIDDEN; void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN;
/* schannel internal interface */ -typedef struct schan_imp_session_opaque *schan_imp_session; +typedef struct schan_session_opaque *schan_session;
typedef struct schan_credentials { @@ -111,40 +113,43 @@ struct schan_transport struct schan_buffers out; };
-char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) DECLSPEC_HIDDEN; -extern int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) DECLSPEC_HIDDEN; -extern int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) DECLSPEC_HIDDEN; - -extern schan_imp_session schan_session_for_transport(struct schan_transport* t) DECLSPEC_HIDDEN; - -/* schannel implementation interface */ -extern BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) DECLSPEC_HIDDEN; -extern void schan_imp_dispose_session(schan_imp_session session) DECLSPEC_HIDDEN; -extern void schan_imp_set_session_transport(schan_imp_session session, - struct schan_transport *t) DECLSPEC_HIDDEN; -extern void schan_imp_set_session_target(schan_imp_session session, const char *target) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_handshake(schan_imp_session session) DECLSPEC_HIDDEN; -extern unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) DECLSPEC_HIDDEN; -extern unsigned int schan_imp_get_max_message_size(schan_imp_session session) DECLSPEC_HIDDEN; -extern ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, - SecPkgContext_ConnectionInfo *info) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session, - SecPkgContext_Bindings *bindings) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE, - PCCERT_CONTEXT *cert) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, - SIZE_T *length) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, - SIZE_T *length) DECLSPEC_HIDDEN; -extern BOOL schan_imp_allocate_certificate_credentials(schan_credentials *, const CERT_CONTEXT *) DECLSPEC_HIDDEN; -extern void schan_imp_free_certificate_credentials(schan_credentials*) DECLSPEC_HIDDEN; -extern DWORD schan_imp_enabled_protocols(void) DECLSPEC_HIDDEN; -extern BOOL schan_imp_init(void) DECLSPEC_HIDDEN; -extern void schan_imp_deinit(void) DECLSPEC_HIDDEN; -extern void schan_imp_set_application_protocols(schan_imp_session, unsigned char *, unsigned int) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session, - SecPkgContext_ApplicationProtocol *) DECLSPEC_HIDDEN; -extern SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session, unsigned int) DECLSPEC_HIDDEN; - -#endif /* ndef __SECUR32_PRIV_H__ */ +struct schan_cert_list +{ + unsigned int count; + CERT_BLOB *certs; +}; + +struct schan_funcs +{ + BOOL (CDECL *allocate_certificate_credentials)(schan_credentials *, const CERT_CONTEXT *, const DATA_BLOB *); + BOOL (CDECL *create_session)(schan_session *, schan_credentials *); + void (CDECL *dispose_session)(schan_session); + void (CDECL *free_certificate_credentials)(schan_credentials *); + SECURITY_STATUS (CDECL *get_application_protocol)(schan_session, SecPkgContext_ApplicationProtocol *); + SECURITY_STATUS (CDECL *get_connection_info)(schan_session, SecPkgContext_ConnectionInfo *); + DWORD (CDECL *get_enabled_protocols)(void); + ALG_ID (CDECL *get_key_signature_algorithm)(schan_session); + unsigned int (CDECL *get_max_message_size)(schan_session); + unsigned int (CDECL *get_session_cipher_block_size)(schan_session); + SECURITY_STATUS (CDECL *get_session_peer_certificate)(schan_session, struct schan_cert_list *); + SECURITY_STATUS (CDECL *get_unique_channel_binding)(schan_session, SecPkgContext_Bindings *); + SECURITY_STATUS (CDECL *handshake)(schan_session session); + SECURITY_STATUS (CDECL *recv)(schan_session, void *, SIZE_T *); + SECURITY_STATUS (CDECL *send)(schan_session, const void *, SIZE_T *); + void (CDECL *set_application_protocols)(schan_session, unsigned char *, unsigned int); + SECURITY_STATUS (CDECL *set_dtls_mtu)(schan_session, unsigned int); + void (CDECL *set_session_target)(schan_session, const char *); + void (CDECL *set_session_transport)(schan_session, struct schan_transport *); +}; + +struct schan_callbacks +{ + char * (CDECL *get_buffer)(const struct schan_transport *, struct schan_buffers *, SIZE_T *); + schan_session (CDECL *get_session_for_transport)(struct schan_transport *); + int CDECL (CDECL *pull)(struct schan_transport *, void *, size_t *); + int CDECL (CDECL *push)(struct schan_transport *, const void *, size_t *); +}; + +extern const struct schan_funcs *schan_funcs; + +#endif /* __SECUR32_PRIV_H__ */