[PATCH] secur32: Add support for client certificate authentication.
Hans Leidekker
hans at codeweavers.com
Thu Feb 7 03:52:11 CST 2019
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/secur32/schannel.c | 92 ++++++-------
dlls/secur32/schannel_gnutls.c | 303 ++++++++++++++++++++++++++++++++++++++++-
dlls/secur32/schannel_macosx.c | 4 +-
dlls/secur32/secur32_priv.h | 2 +-
4 files changed, 345 insertions(+), 56 deletions(-)
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 792d7804b3..8063fd4d6b 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -338,26 +338,26 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesW(
return ret;
}
-static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred)
+static SECURITY_STATUS get_cert(const SCHANNEL_CRED *cred, CERT_CONTEXT const **cert)
{
- SECURITY_STATUS st;
+ SECURITY_STATUS status;
DWORD i;
- TRACE("dwVersion = %d\n", schanCred->dwVersion);
- TRACE("cCreds = %d\n", schanCred->cCreds);
- TRACE("hRootStore = %p\n", schanCred->hRootStore);
- TRACE("cMappers = %d\n", schanCred->cMappers);
- TRACE("cSupportedAlgs = %d:\n", schanCred->cSupportedAlgs);
- for (i = 0; i < schanCred->cSupportedAlgs; i++)
- TRACE("%08x\n", schanCred->palgSupportedAlgs[i]);
- TRACE("grbitEnabledProtocols = %08x\n", schanCred->grbitEnabledProtocols);
- TRACE("dwMinimumCipherStrength = %d\n", schanCred->dwMinimumCipherStrength);
- TRACE("dwMaximumCipherStrength = %d\n", schanCred->dwMaximumCipherStrength);
- TRACE("dwSessionLifespan = %d\n", schanCred->dwSessionLifespan);
- TRACE("dwFlags = %08x\n", schanCred->dwFlags);
- TRACE("dwCredFormat = %d\n", schanCred->dwCredFormat);
-
- switch (schanCred->dwVersion)
+ TRACE("dwVersion = %u\n", cred->dwVersion);
+ TRACE("cCreds = %u\n", cred->cCreds);
+ TRACE("paCred = %p\n", cred->paCred);
+ TRACE("hRootStore = %p\n", cred->hRootStore);
+ TRACE("cMappers = %u\n", cred->cMappers);
+ TRACE("cSupportedAlgs = %u:\n", cred->cSupportedAlgs);
+ for (i = 0; i < cred->cSupportedAlgs; i++) TRACE("%08x\n", cred->palgSupportedAlgs[i]);
+ TRACE("grbitEnabledProtocols = %08x\n", cred->grbitEnabledProtocols);
+ TRACE("dwMinimumCipherStrength = %u\n", cred->dwMinimumCipherStrength);
+ TRACE("dwMaximumCipherStrength = %u\n", cred->dwMaximumCipherStrength);
+ TRACE("dwSessionLifespan = %u\n", cred->dwSessionLifespan);
+ TRACE("dwFlags = %08x\n", cred->dwFlags);
+ TRACE("dwCredFormat = %u\n", cred->dwCredFormat);
+
+ switch (cred->dwVersion)
{
case SCH_CRED_V3:
case SCHANNEL_CRED_VERSION:
@@ -366,29 +366,24 @@ static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred)
return SEC_E_INTERNAL_ERROR;
}
- if (schanCred->cCreds == 0)
- st = SEC_E_NO_CREDENTIALS;
- else if (schanCred->cCreds > 1)
- st = SEC_E_UNKNOWN_CREDENTIALS;
+ if (!cred->cCreds) status = SEC_E_NO_CREDENTIALS;
+ else if (cred->cCreds > 1) status = SEC_E_UNKNOWN_CREDENTIALS;
else
{
- DWORD keySpec;
- HCRYPTPROV csp;
- BOOL ret, freeCSP;
-
- ret = CryptAcquireCertificatePrivateKey(schanCred->paCred[0],
- 0, /* FIXME: what flags to use? */ NULL,
- &csp, &keySpec, &freeCSP);
- if (ret)
+ DWORD spec;
+ HCRYPTPROV prov;
+ BOOL free;
+
+ if (CryptAcquireCertificatePrivateKey(cred->paCred[0], CRYPT_ACQUIRE_CACHE_FLAG, NULL, &prov, &spec, &free))
{
- st = SEC_E_OK;
- if (freeCSP)
- CryptReleaseContext(csp, 0);
+ if (free) CryptReleaseContext(prov, 0);
+ *cert = cred->paCred[0];
+ status = SEC_E_OK;
}
- else
- st = SEC_E_UNKNOWN_CREDENTIALS;
+ else status = SEC_E_UNKNOWN_CREDENTIALS;
}
- return st;
+
+ return status;
}
static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred,
@@ -397,17 +392,18 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
struct schan_credentials *creds;
unsigned enabled_protocols;
ULONG_PTR handle;
- SECURITY_STATUS st = SEC_E_OK;
+ SECURITY_STATUS status = SEC_E_OK;
+ const CERT_CONTEXT *cert = NULL;
TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
if (schanCred)
{
- st = schan_CheckCreds(schanCred);
- if (st != SEC_E_OK && st != SEC_E_NO_CREDENTIALS)
- return st;
+ status = get_cert(schanCred, &cert);
+ if (status != SEC_E_OK && status != SEC_E_NO_CREDENTIALS)
+ return status;
- st = SEC_E_OK;
+ status = SEC_E_OK;
}
read_config();
@@ -420,9 +416,6 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
return SEC_E_NO_AUTHENTICATING_AUTHORITY;
}
- /* For now, the only thing I'm interested in is the direction of the
- * connection, so just store it.
- */
creds = heap_alloc(sizeof(*creds));
if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
@@ -430,7 +423,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
if (handle == SCHAN_INVALID_HANDLE) goto fail;
creds->credential_use = SECPKG_CRED_OUTBOUND;
- if (!schan_imp_allocate_certificate_credentials(creds))
+ if (!schan_imp_allocate_certificate_credentials(creds, cert))
{
schan_free_handle(handle, SCHAN_HANDLE_CRED);
goto fail;
@@ -447,7 +440,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
ptsExpiry->HighPart = 0;
}
- return st;
+ return status;
fail:
heap_free(creds);
@@ -457,14 +450,15 @@ fail:
static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred,
PCredHandle phCredential, PTimeStamp ptsExpiry)
{
- SECURITY_STATUS st;
+ SECURITY_STATUS status;
+ const CERT_CONTEXT *cert = NULL;
TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
if (!schanCred) return SEC_E_NO_CREDENTIALS;
- st = schan_CheckCreds(schanCred);
- if (st == SEC_E_OK)
+ status = get_cert(schanCred, &cert);
+ if (status == SEC_E_OK)
{
ULONG_PTR handle;
struct schan_credentials *creds;
@@ -485,7 +479,7 @@ static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schan
/* FIXME: get expiry from cert */
}
- return st;
+ return status;
}
static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse,
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index cb90d1c40d..ddb10aca8c 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -24,18 +24,24 @@
#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 "windef.h"
#include "winbase.h"
#include "sspi.h"
#include "schannel.h"
+#include "lmcons.h"
+#include "winreg.h"
#include "secur32_priv.h"
+
#include "wine/debug.h"
#include "wine/library.h"
+#include "wine/unicode.h"
#if defined(SONAME_LIBGNUTLS) && !defined(HAVE_SECURITY_SECURITY_H)
@@ -43,7 +49,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(secur32);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
/* Not present in gnutls version < 2.9.10. */
-static int (*pgnutls_cipher_get_block_size)(gnutls_cipher_algorithm_t algorithm);
+static int (*pgnutls_cipher_get_block_size)(gnutls_cipher_algorithm_t);
+
+/* Not present in gnutls version < 3.4.0. */
+static int (*pgnutls_privkey_export_x509)(gnutls_privkey_t, gnutls_x509_privkey_t *);
static void *libgnutls_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
@@ -52,6 +61,7 @@ MAKE_FUNCPTR(gnutls_alert_get_name);
MAKE_FUNCPTR(gnutls_certificate_allocate_credentials);
MAKE_FUNCPTR(gnutls_certificate_free_credentials);
MAKE_FUNCPTR(gnutls_certificate_get_peers);
+MAKE_FUNCPTR(gnutls_certificate_set_x509_key);
MAKE_FUNCPTR(gnutls_cipher_get);
MAKE_FUNCPTR(gnutls_cipher_get_key_size);
MAKE_FUNCPTR(gnutls_credentials_set);
@@ -68,6 +78,9 @@ MAKE_FUNCPTR(gnutls_mac_get_key_size);
MAKE_FUNCPTR(gnutls_perror);
MAKE_FUNCPTR(gnutls_protocol_get_version);
MAKE_FUNCPTR(gnutls_priority_set_direct);
+MAKE_FUNCPTR(gnutls_privkey_deinit);
+MAKE_FUNCPTR(gnutls_privkey_import_rsa_raw);
+MAKE_FUNCPTR(gnutls_privkey_init);
MAKE_FUNCPTR(gnutls_record_get_max_size);
MAKE_FUNCPTR(gnutls_record_recv);
MAKE_FUNCPTR(gnutls_record_send);
@@ -77,6 +90,10 @@ MAKE_FUNCPTR(gnutls_transport_set_errno);
MAKE_FUNCPTR(gnutls_transport_set_ptr);
MAKE_FUNCPTR(gnutls_transport_set_pull_function);
MAKE_FUNCPTR(gnutls_transport_set_push_function);
+MAKE_FUNCPTR(gnutls_x509_crt_deinit);
+MAKE_FUNCPTR(gnutls_x509_crt_import);
+MAKE_FUNCPTR(gnutls_x509_crt_init);
+MAKE_FUNCPTR(gnutls_x509_privkey_deinit);
#undef MAKE_FUNCPTR
#if GNUTLS_VERSION_MAJOR < 3
@@ -115,6 +132,12 @@ static int compat_cipher_get_block_size(gnutls_cipher_algorithm_t cipher)
}
}
+static int compat_gnutls_privkey_export_x509(gnutls_privkey_t privkey, gnutls_x509_privkey_t *key)
+{
+ FIXME("\n");
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
static ssize_t schan_pull_adapter(gnutls_transport_ptr_t transport,
void *buff, size_t buff_len)
{
@@ -556,12 +579,271 @@ again:
return SEC_E_OK;
}
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c)
+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};
+ DWORD size;
+ CERT_KEY_CONTEXT keyctx;
+ CRYPT_KEY_PROV_INFO *prov;
+ WCHAR username[UNLEN + 1], *ret = NULL;
+ DWORD len = ARRAY_SIZE(username);
+
+ size = sizeof(keyctx);
+ 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
+ {
+ size = 0;
+ if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) return NULL;
+ if (!(prov = heap_alloc(size))) return NULL;
+ if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, 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;
+ }
+
+ 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);
+ heap_free(path);
+ return ret;
+}
+
+static inline void reverse_bytes(BYTE *buf, ULONG len)
{
- int ret = pgnutls_certificate_allocate_credentials((gnutls_certificate_credentials_t*)&c->credentials);
+ BYTE tmp;
+ ULONG i;
+ for (i = 0; i < len / 2; i++)
+ {
+ tmp = buf[i];
+ buf[i] = buf[len - i - 1];
+ buf[len - i - 1] = tmp;
+ }
+}
+
+static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *buflen)
+{
+ comp->data = data;
+ comp->size = len;
+ reverse_bytes(comp->data, comp->size);
+ if (comp->data[0] & 0x80) /* add leading 0 byte if most significant bit is set */
+ {
+ memmove(comp->data + 1, comp->data, *buflen);
+ comp->data[0] = 0;
+ comp->size++;
+ }
+ *buflen -= comp->size;
+ return comp->size;
+}
+
+static gnutls_x509_privkey_t get_x509_key(const CERT_CONTEXT *ctx)
+{
+ 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;
+ RSAPUBKEY *rsakey;
+ DWORD size;
+ int ret;
+
+ if (!(buffer = get_key_blob(ctx, &size))) return NULL;
+ if (size < sizeof(BLOBHEADER)) goto done;
+
+ rsakey = (RSAPUBKEY *)(buffer + sizeof(BLOBHEADER));
+ TRACE("RSA key bitlen %u pubexp %u\n", rsakey->bitlen, rsakey->pubexp);
+
+ size -= sizeof(BLOBHEADER) + FIELD_OFFSET(RSAPUBKEY, pubexp);
+ set_component(&e, (BYTE *)&rsakey->pubexp, sizeof(rsakey->pubexp), &size);
+
+ ptr = (BYTE *)(rsakey + 1);
+ ptr += set_component(&m, ptr, rsakey->bitlen / 8, &size);
+ ptr += set_component(&p, ptr, rsakey->bitlen / 16, &size);
+ ptr += set_component(&q, ptr, rsakey->bitlen / 16, &size);
+ ptr += set_component(&e1, ptr, rsakey->bitlen / 16, &size);
+ ptr += set_component(&e2, ptr, rsakey->bitlen / 16, &size);
+ ptr += set_component(&u, ptr, rsakey->bitlen / 16, &size);
+ ptr += set_component(&d, ptr, rsakey->bitlen / 8, &size);
+
+ 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;
+ }
+
+ if ((ret = pgnutls_privkey_export_x509(key, &x509key)) < 0)
+ {
+ pgnutls_perror(ret);
+ }
+
+done:
+ heap_free(buffer);
+ pgnutls_privkey_deinit(key);
+ return x509key;
+}
+
+static gnutls_x509_crt_t get_x509_crt(const CERT_CONTEXT *ctx)
+{
+ gnutls_datum_t data;
+ gnutls_x509_crt_t crt;
+ int ret;
+
+ if (!ctx) return FALSE;
+ if (ctx->dwCertEncodingType != X509_ASN_ENCODING)
+ {
+ FIXME("encoding type %u not supported\n", ctx->dwCertEncodingType);
+ return NULL;
+ }
+
+ if ((ret = pgnutls_x509_crt_init(&crt)) < 0)
+ {
+ pgnutls_perror(ret);
+ return NULL;
+ }
+
+ data.data = ctx->pbCertEncoded;
+ data.size = ctx->cbCertEncoded;
+ if ((ret = pgnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_DER)) < 0)
+ {
+ pgnutls_perror(ret);
+ pgnutls_x509_crt_deinit(crt);
+ return NULL;
+ }
+
+ return crt;
+}
+
+BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx)
+{
+ gnutls_certificate_credentials_t creds;
+ gnutls_x509_crt_t crt;
+ gnutls_x509_privkey_t key;
+ int ret;
+
+ ret = pgnutls_certificate_allocate_credentials(&creds);
+ if (ret != GNUTLS_E_SUCCESS)
+ {
+ pgnutls_perror(ret);
+ return FALSE;
+ }
+
+ if (!ctx)
+ {
+ c->credentials = creds;
+ return TRUE;
+ }
+
+ if (!(crt = get_x509_crt(ctx)))
+ {
+ pgnutls_certificate_free_credentials(creds);
+ return FALSE;
+ }
+
+ if (!(key = get_x509_key(ctx)))
+ {
+ pgnutls_x509_crt_deinit(crt);
+ pgnutls_certificate_free_credentials(creds);
+ return FALSE;
+ }
+
+ ret = pgnutls_certificate_set_x509_key(creds, &crt, 1, key);
+ pgnutls_x509_privkey_deinit(key);
+ pgnutls_x509_crt_deinit(crt);
if (ret != GNUTLS_E_SUCCESS)
+ {
pgnutls_perror(ret);
- return (ret == GNUTLS_E_SUCCESS);
+ pgnutls_certificate_free_credentials(creds);
+ return FALSE;
+ }
+
+ c->credentials = creds;
+ return TRUE;
}
void schan_imp_free_certificate_credentials(schan_credentials *c)
@@ -597,6 +879,7 @@ BOOL schan_imp_init(void)
LOAD_FUNCPTR(gnutls_certificate_allocate_credentials)
LOAD_FUNCPTR(gnutls_certificate_free_credentials)
LOAD_FUNCPTR(gnutls_certificate_get_peers)
+ LOAD_FUNCPTR(gnutls_certificate_set_x509_key)
LOAD_FUNCPTR(gnutls_cipher_get)
LOAD_FUNCPTR(gnutls_cipher_get_key_size)
LOAD_FUNCPTR(gnutls_credentials_set)
@@ -613,6 +896,9 @@ BOOL schan_imp_init(void)
LOAD_FUNCPTR(gnutls_perror)
LOAD_FUNCPTR(gnutls_protocol_get_version)
LOAD_FUNCPTR(gnutls_priority_set_direct)
+ LOAD_FUNCPTR(gnutls_privkey_deinit)
+ LOAD_FUNCPTR(gnutls_privkey_import_rsa_raw)
+ LOAD_FUNCPTR(gnutls_privkey_init)
LOAD_FUNCPTR(gnutls_record_get_max_size);
LOAD_FUNCPTR(gnutls_record_recv);
LOAD_FUNCPTR(gnutls_record_send);
@@ -622,6 +908,10 @@ BOOL schan_imp_init(void)
LOAD_FUNCPTR(gnutls_transport_set_ptr)
LOAD_FUNCPTR(gnutls_transport_set_pull_function)
LOAD_FUNCPTR(gnutls_transport_set_push_function)
+ LOAD_FUNCPTR(gnutls_x509_crt_deinit)
+ LOAD_FUNCPTR(gnutls_x509_crt_import)
+ LOAD_FUNCPTR(gnutls_x509_crt_init)
+ LOAD_FUNCPTR(gnutls_x509_privkey_deinit)
#undef LOAD_FUNCPTR
if (!(pgnutls_cipher_get_block_size = wine_dlsym(libgnutls_handle, "gnutls_cipher_get_block_size", NULL, 0)))
@@ -629,6 +919,11 @@ BOOL schan_imp_init(void)
WARN("gnutls_cipher_get_block_size not found\n");
pgnutls_cipher_get_block_size = compat_cipher_get_block_size;
}
+ if (!(pgnutls_privkey_export_x509 = wine_dlsym(libgnutls_handle, "gnutls_privkey_export_x509", NULL, 0)))
+ {
+ WARN("gnutls_privkey_export_x509 not found\n");
+ pgnutls_privkey_export_x509 = compat_gnutls_privkey_export_x509;
+ }
ret = pgnutls_global_init();
if (ret != GNUTLS_E_SUCCESS)
diff --git a/dlls/secur32/schannel_macosx.c b/dlls/secur32/schannel_macosx.c
index 29d2f65172..981e4fb5ad 100644
--- a/dlls/secur32/schannel_macosx.c
+++ b/dlls/secur32/schannel_macosx.c
@@ -1185,9 +1185,9 @@ SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
return SEC_E_OK;
}
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c)
+BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *cert)
{
- /* The certificate is never really used for anything. */
+ if (cert) FIXME("no support for certificate credentials on this platform\n");
c->credentials = NULL;
return TRUE;
}
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index 4566fe2446..a62d6cb2df 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -247,7 +247,7 @@ extern SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buf
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*) 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;
--
2.11.0
More information about the wine-devel
mailing list