-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
gh-80192: Use windows api if ssl cert verification fails #127622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
9d28198
d3da5df
b8f5bd5
c9ad0a3
80b21bd
2435d4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fixed valid ssl certificates being rejected. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2996,6 +2996,119 @@ static PyType_Spec PySSLSocket_spec = { | |
.slots = PySSLSocket_slots, | ||
}; | ||
|
||
#ifdef _MSC_VER | ||
static const unsigned char * | ||
_get_cert_bytes(const X509 *cert, int *length) | ||
{ | ||
unsigned char *cert_bytes; | ||
int cert_bytes_length = i2d_X509(cert, NULL); | ||
if (cert_bytes_length <= 0) | ||
{ | ||
return NULL; | ||
} | ||
|
||
cert_bytes = PyMem_RawMalloc(cert_bytes_length); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to use pymalloc ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using PyMem_Malloc I got the following error in my sample program: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured. It might be worth adding a comment mentioning that the GIL isn't held (so no Python APIs can get called). |
||
if (cert_bytes == NULL) | ||
{ | ||
return NULL; | ||
} | ||
|
||
if (i2d_X509(cert, &cert_bytes) <= 0) | ||
{ | ||
return NULL; | ||
} | ||
|
||
*length = cert_bytes_length; | ||
|
||
/* i2d_X509 moves the input pointer to the end of the data */ | ||
return cert_bytes - cert_bytes_length; | ||
} | ||
|
||
|
||
static int | ||
_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) | ||
{ | ||
int ret = 0; | ||
/* windows api calls below do not check for hostname mismatch */ | ||
if (preverify_ok || X509_STORE_CTX_get_error(ctx) == X509_V_ERR_HOSTNAME_MISMATCH) | ||
{ | ||
return preverify_ok; | ||
} | ||
|
||
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL); | ||
ZeroIntensity marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
if (store == NULL) | ||
{ | ||
return ret; | ||
} | ||
|
||
int cert_bytes_length; | ||
const unsigned char *cert_bytes = _get_cert_bytes(X509_STORE_CTX_get_current_cert(ctx), &cert_bytes_length); | ||
if (cert_bytes == NULL) | ||
{ | ||
goto error_1; | ||
} | ||
|
||
PCCERT_CONTEXT primary_context = NULL; | ||
if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, cert_bytes, cert_bytes_length, CERT_STORE_ADD_REPLACE_EXISTING, &primary_context)) | ||
{ | ||
goto error_2; | ||
} | ||
PCCERT_CHAIN_CONTEXT chain_context = NULL; | ||
CERT_CHAIN_PARA parameters = {0}; | ||
if (!CertGetCertificateChain(NULL, primary_context, NULL, store, ¶meters, 0, NULL, &chain_context)) | ||
{ | ||
goto error_3; | ||
} | ||
CERT_CHAIN_POLICY_PARA policy_parameters = {0}; | ||
CERT_CHAIN_POLICY_STATUS policy_status = {0}; | ||
if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context, &policy_parameters, &policy_status)) | ||
{ | ||
goto error_4; | ||
} | ||
|
||
switch(policy_status.dwError) { | ||
case CERT_TRUST_NO_ERROR: | ||
ret = 1; | ||
break; | ||
case TRUST_E_CERT_SIGNATURE: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_SIGNATURE_FAILURE); | ||
break; | ||
case CERT_E_UNTRUSTEDROOT: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_UNTRUSTED); | ||
break; | ||
case CERT_E_CHAINING: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); | ||
break; | ||
case CERT_E_EXPIRED: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_HAS_EXPIRED); | ||
break; | ||
case CERT_E_INVALID_POLICY: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_POLICY_EXTENSION); | ||
break; | ||
case CERT_E_WRONG_USAGE: | ||
case CERT_E_CRITICAL: | ||
case CERT_E_PURPOSE: | ||
|
||
case CERT_E_ROLE: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_INVALID_PURPOSE); | ||
break; | ||
case CERT_E_VALIDITYPERIODNESTING: | ||
default: | ||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); | ||
} | ||
error_4: | ||
CertFreeCertificateChain(chain_context); | ||
error_3: | ||
CertFreeCertificateContext(primary_context); | ||
error_2: | ||
PyMem_RawFree((void *)cert_bytes); | ||
error_1: | ||
CertCloseStore(store, 0); | ||
return ret; | ||
} | ||
#else | ||
#define _verify_callback NULL | ||
#endif | ||
|
||
/* | ||
* _SSLContext objects | ||
*/ | ||
|
@@ -3024,7 +3137,7 @@ _set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n) | |
/* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for | ||
* server sockets and SSL_set_post_handshake_auth() for client. */ | ||
|
||
SSL_CTX_set_verify(self->ctx, mode, NULL); | ||
SSL_CTX_set_verify(self->ctx, mode, _verify_callback); | ||
return 0; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use a reference:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference added
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would see a broader text, e.g. the PR verifies certifications rejected by OpenSSL by additional calls to Windows specific API functions.
The exact proposed text is definitely not fine, but you have got my idea.