summaryrefslogtreecommitdiffstats
path: root/Modules/_ssl.c
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2021-04-26 13:01:40 (GMT)
committerGitHub <noreply@github.com>2021-04-26 13:01:40 (GMT)
commit666991fc598bc312d72aff0078ecb553f0a968f1 (patch)
tree7fa615cd3d075120eb98cf4cea879a753c06e33f /Modules/_ssl.c
parent3c586ca500854476e6eff06713236faff233d035 (diff)
downloadcpython-666991fc598bc312d72aff0078ecb553f0a968f1.zip
cpython-666991fc598bc312d72aff0078ecb553f0a968f1.tar.gz
cpython-666991fc598bc312d72aff0078ecb553f0a968f1.tar.bz2
bpo-18233: Add internal methods to access peer chain (GH-25467)
The internal `_ssl._SSLSocket` object now provides methods to retrieve the peer cert chain and verified cert chain as a list of Certificate objects. Certificate objects have methods to convert the cert to a dict, PEM, or DER (ASN.1). These are private APIs for now. There is a slim chance to stabilize the approach and provide a public API for 3.10. Otherwise I'll provide a stable API in 3.11. Signed-off-by: Christian Heimes <christian@python.org>
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r--Modules/_ssl.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index abc5c2c..65370c5 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -1706,6 +1706,9 @@ _certificate_to_der(_sslmodulestate *state, X509 *certificate)
return retval;
}
+#include "_ssl/misc.c"
+#include "_ssl/cert.c"
+
/*[clinic input]
_ssl._test_decode_cert
path: object(converter="PyUnicode_FSConverter")
@@ -1798,6 +1801,70 @@ _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode)
return result;
}
+/*[clinic input]
+_ssl._SSLSocket.get_verified_chain
+
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_get_verified_chain_impl(PySSLSocket *self)
+/*[clinic end generated code: output=802421163cdc3110 input=5fb0714f77e2bd51]*/
+{
+ /* borrowed reference */
+ STACK_OF(X509) *chain = SSL_get0_verified_chain(self->ssl);
+ if (chain == NULL) {
+ Py_RETURN_NONE;
+ }
+ return _PySSL_CertificateFromX509Stack(self->ctx->state, chain, 1);
+}
+
+/*[clinic input]
+_ssl._SSLSocket.get_unverified_chain
+
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_get_unverified_chain_impl(PySSLSocket *self)
+/*[clinic end generated code: output=5acdae414e13f913 input=78c33c360c635cb5]*/
+{
+ PyObject *retval;
+ /* borrowed reference */
+ /* TODO: include SSL_get_peer_certificate() for server-side sockets */
+ STACK_OF(X509) *chain = SSL_get_peer_cert_chain(self->ssl);
+ if (chain == NULL) {
+ Py_RETURN_NONE;
+ }
+ retval = _PySSL_CertificateFromX509Stack(self->ctx->state, chain, 1);
+ if (retval == NULL) {
+ return NULL;
+ }
+ /* OpenSSL does not include peer cert for server side connections */
+ if (self->socket_type == PY_SSL_SERVER) {
+ PyObject *peerobj = NULL;
+ X509 *peer = SSL_get_peer_certificate(self->ssl);
+
+ if (peer == NULL) {
+ peerobj = Py_None;
+ Py_INCREF(peerobj);
+ } else {
+ /* consume X509 reference on success */
+ peerobj = _PySSL_CertificateFromX509(self->ctx->state, peer, 0);
+ if (peerobj == NULL) {
+ X509_free(peer);
+ Py_DECREF(retval);
+ return NULL;
+ }
+ }
+ int res = PyList_Insert(retval, 0, peerobj);
+ Py_DECREF(peerobj);
+ if (res < 0) {
+ Py_DECREF(retval);
+ return NULL;
+ }
+ }
+ return retval;
+}
+
static PyObject *
cipher_to_tuple(const SSL_CIPHER *cipher)
{
@@ -2809,6 +2876,8 @@ static PyMethodDef PySSLMethods[] = {
_SSL__SSLSOCKET_COMPRESSION_METHODDEF
_SSL__SSLSOCKET_SHUTDOWN_METHODDEF
_SSL__SSLSOCKET_VERIFY_CLIENT_POST_HANDSHAKE_METHODDEF
+ _SSL__SSLSOCKET_GET_UNVERIFIED_CHAIN_METHODDEF
+ _SSL__SSLSOCKET_GET_VERIFIED_CHAIN_METHODDEF
{NULL, NULL}
};
@@ -5784,6 +5853,10 @@ sslmodule_init_constants(PyObject *m)
X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS);
#endif
+ /* file types */
+ PyModule_AddIntConstant(m, "ENCODING_PEM", PY_SSL_ENCODING_PEM);
+ PyModule_AddIntConstant(m, "ENCODING_DER", PY_SSL_ENCODING_DER);
+
/* protocol versions */
PyModule_AddIntConstant(m, "PROTO_MINIMUM_SUPPORTED",
PY_PROTO_MINIMUM_SUPPORTED);
@@ -5986,6 +6059,12 @@ sslmodule_init_types(PyObject *module)
if (state->PySSLSession_Type == NULL)
return -1;
+ state->PySSLCertificate_Type = (PyTypeObject *)PyType_FromModuleAndSpec(
+ module, &PySSLCertificate_spec, NULL
+ );
+ if (state->PySSLCertificate_Type == NULL)
+ return -1;
+
if (PyModule_AddType(module, state->PySSLContext_Type))
return -1;
if (PyModule_AddType(module, state->PySSLSocket_Type))
@@ -5994,7 +6073,8 @@ sslmodule_init_types(PyObject *module)
return -1;
if (PyModule_AddType(module, state->PySSLSession_Type))
return -1;
-
+ if (PyModule_AddType(module, state->PySSLCertificate_Type))
+ return -1;
return 0;
}
@@ -6017,6 +6097,7 @@ sslmodule_traverse(PyObject *m, visitproc visit, void *arg)
Py_VISIT(state->PySSLSocket_Type);
Py_VISIT(state->PySSLMemoryBIO_Type);
Py_VISIT(state->PySSLSession_Type);
+ Py_VISIT(state->PySSLCertificate_Type);
Py_VISIT(state->PySSLErrorObject);
Py_VISIT(state->PySSLCertVerificationErrorObject);
Py_VISIT(state->PySSLZeroReturnErrorObject);
@@ -6041,6 +6122,7 @@ sslmodule_clear(PyObject *m)
Py_CLEAR(state->PySSLSocket_Type);
Py_CLEAR(state->PySSLMemoryBIO_Type);
Py_CLEAR(state->PySSLSession_Type);
+ Py_CLEAR(state->PySSLCertificate_Type);
Py_CLEAR(state->PySSLErrorObject);
Py_CLEAR(state->PySSLCertVerificationErrorObject);
Py_CLEAR(state->PySSLZeroReturnErrorObject);