mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-05 22:30:15 +00:00
secur32: Add support for client certificate authentication.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
88b20b2dee
commit
16d9f62bdf
|
@ -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);
|
||||
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 (schanCred->dwVersion)
|
||||
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;
|
||||
DWORD spec;
|
||||
HCRYPTPROV prov;
|
||||
BOOL free;
|
||||
|
||||
ret = CryptAcquireCertificatePrivateKey(schanCred->paCred[0],
|
||||
0, /* FIXME: what flags to use? */ NULL,
|
||||
&csp, &keySpec, &freeCSP);
|
||||
if (ret)
|
||||
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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
int ret = pgnutls_certificate_allocate_credentials((gnutls_certificate_credentials_t*)&c->credentials);
|
||||
if (ret != GNUTLS_E_SUCCESS)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return (ret == GNUTLS_E_SUCCESS);
|
||||
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);
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue