winhttp: Check the certificate in an https connection using the crypto api.
This commit is contained in:
parent
48a7580135
commit
82d07c4051
|
@ -212,15 +212,156 @@ static int sock_get_error( int err )
|
|||
}
|
||||
|
||||
#ifdef SONAME_LIBSSL
|
||||
static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
|
||||
{
|
||||
unsigned char *buffer, *p;
|
||||
int len;
|
||||
BOOL malloc = FALSE;
|
||||
PCCERT_CONTEXT ret;
|
||||
|
||||
p = NULL;
|
||||
if ((len = pi2d_X509( cert, &p )) < 0) return NULL;
|
||||
/*
|
||||
* SSL 0.9.7 and above malloc the buffer if it is null.
|
||||
* however earlier version do not and so we would need to alloc the buffer.
|
||||
*
|
||||
* see the i2d_X509 man page for more details.
|
||||
*/
|
||||
if (!p)
|
||||
{
|
||||
if (!(buffer = heap_alloc( len ))) return NULL;
|
||||
p = buffer;
|
||||
len = pi2d_X509( cert, &p );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = p;
|
||||
malloc = TRUE;
|
||||
}
|
||||
|
||||
ret = CertCreateCertificateContext( X509_ASN_ENCODING, buffer, len );
|
||||
|
||||
if (malloc) free( buffer );
|
||||
else heap_free( buffer );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
|
||||
WCHAR *server )
|
||||
{
|
||||
BOOL ret;
|
||||
CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
|
||||
PCCERT_CHAIN_CONTEXT chain;
|
||||
char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
|
||||
char *server_auth[] = { oid_server_auth };
|
||||
DWORD err;
|
||||
|
||||
TRACE("verifying %s\n", debugstr_w( server ));
|
||||
chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
|
||||
chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
|
||||
if ((ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara, 0,
|
||||
NULL, &chain )))
|
||||
{
|
||||
if (chain->TrustStatus.dwErrorStatus)
|
||||
{
|
||||
if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
|
||||
err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
|
||||
else if (chain->TrustStatus.dwErrorStatus &
|
||||
CERT_TRUST_IS_UNTRUSTED_ROOT)
|
||||
err = ERROR_WINHTTP_SECURE_INVALID_CA;
|
||||
else if ((chain->TrustStatus.dwErrorStatus &
|
||||
CERT_TRUST_IS_OFFLINE_REVOCATION) ||
|
||||
(chain->TrustStatus.dwErrorStatus &
|
||||
CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
|
||||
err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
|
||||
else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
|
||||
err = ERROR_WINHTTP_SECURE_CERT_REVOKED;
|
||||
else if (chain->TrustStatus.dwErrorStatus &
|
||||
CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
|
||||
err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
|
||||
else
|
||||
err = ERROR_WINHTTP_SECURE_INVALID_CERT;
|
||||
set_last_error( err );
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
CERT_CHAIN_POLICY_PARA policyPara;
|
||||
SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
|
||||
CERT_CHAIN_POLICY_STATUS policyStatus;
|
||||
|
||||
sslExtraPolicyPara.cbSize = sizeof(sslExtraPolicyPara);
|
||||
sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
|
||||
sslExtraPolicyPara.pwszServerName = server;
|
||||
policyPara.cbSize = sizeof(policyPara);
|
||||
policyPara.dwFlags = 0;
|
||||
policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
|
||||
ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
|
||||
chain, &policyPara,
|
||||
&policyStatus );
|
||||
/* Any error in the policy status indicates that the
|
||||
* policy couldn't be verified.
|
||||
*/
|
||||
if (ret && policyStatus.dwError)
|
||||
{
|
||||
if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
|
||||
err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
|
||||
else
|
||||
err = ERROR_WINHTTP_SECURE_INVALID_CERT;
|
||||
set_last_error( err );
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
CertFreeCertificateChain( chain );
|
||||
}
|
||||
TRACE("returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
|
||||
{
|
||||
SSL *ssl;
|
||||
WCHAR *server;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
ssl = pX509_STORE_CTX_get_ex_data( ctx, pSSL_get_ex_data_X509_STORE_CTX_idx() );
|
||||
server = pSSL_get_ex_data( ssl, hostname_idx );
|
||||
FIXME("verify %s\n", debugstr_w(server));
|
||||
return preverify_ok;
|
||||
if (preverify_ok)
|
||||
{
|
||||
HCERTSTORE store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0,
|
||||
CERT_STORE_CREATE_NEW_FLAG, NULL );
|
||||
|
||||
if (store)
|
||||
{
|
||||
X509 *cert;
|
||||
int i;
|
||||
PCCERT_CONTEXT endCert = NULL;
|
||||
|
||||
ret = TRUE;
|
||||
for (i = 0; ret && i < ctx->chain->num; i++)
|
||||
{
|
||||
PCCERT_CONTEXT context;
|
||||
|
||||
cert = (X509 *)ctx->chain->data[i];
|
||||
if ((context = X509_to_cert_context( cert )))
|
||||
{
|
||||
if (i == 0)
|
||||
ret = CertAddCertificateContextToStore( store, context,
|
||||
CERT_STORE_ADD_ALWAYS, &endCert );
|
||||
else
|
||||
ret = CertAddCertificateContextToStore( store, context,
|
||||
CERT_STORE_ADD_ALWAYS, NULL );
|
||||
CertFreeCertificateContext( context );
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
ret = netconn_verify_cert( endCert, store, server );
|
||||
CertFreeCertificateContext( endCert );
|
||||
CertCloseStore( store, 0 );
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -794,39 +935,12 @@ const void *netconn_get_certificate( netconn_t *conn )
|
|||
{
|
||||
#ifdef SONAME_LIBSSL
|
||||
X509 *cert;
|
||||
unsigned char *buffer, *p;
|
||||
int len;
|
||||
BOOL malloc = FALSE;
|
||||
const CERT_CONTEXT *ret;
|
||||
|
||||
if (!conn->secure) return NULL;
|
||||
|
||||
if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) return NULL;
|
||||
p = NULL;
|
||||
if ((len = pi2d_X509( cert, &p )) < 0) return NULL;
|
||||
/*
|
||||
* SSL 0.9.7 and above malloc the buffer if it is null.
|
||||
* however earlier version do not and so we would need to alloc the buffer.
|
||||
*
|
||||
* see the i2d_X509 man page for more details.
|
||||
*/
|
||||
if (!p)
|
||||
{
|
||||
if (!(buffer = heap_alloc( len ))) return NULL;
|
||||
p = buffer;
|
||||
len = pi2d_X509( cert, &p );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = p;
|
||||
malloc = TRUE;
|
||||
}
|
||||
|
||||
ret = CertCreateCertificateContext( X509_ASN_ENCODING, buffer, len );
|
||||
|
||||
if (malloc) free( buffer );
|
||||
else heap_free( buffer );
|
||||
|
||||
ret = X509_to_cert_context( cert );
|
||||
return ret;
|
||||
#else
|
||||
return NULL;
|
||||
|
|
Loading…
Reference in New Issue