[Python-checkins] cpython: Issue #17134: Add ssl.enum_cert_store() as interface to Windows' cert store.
christian.heimes
python-checkins at python.org
Sun Jun 9 19:03:42 CEST 2013
http://hg.python.org/cpython/rev/10d325f674f5
changeset: 84071:10d325f674f5
user: Christian Heimes <christian at cheimes.de>
date: Sun Jun 09 19:03:31 2013 +0200
summary:
Issue #17134: Add ssl.enum_cert_store() as interface to Windows' cert store.
files:
Doc/library/ssl.rst | 23 ++++
Lib/ssl.py | 4 +
Lib/test/test_ssl.py | 23 ++++
Misc/NEWS | 2 +
Modules/_ssl.c | 134 +++++++++++++++++++++++++++-
PC/VS9.0/_socket.vcproj | 16 +-
PCbuild/_ssl.vcxproj | 16 +-
7 files changed, 201 insertions(+), 17 deletions(-)
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -359,6 +359,20 @@
.. versionadded:: 3.4
+.. function:: enum_cert_store(store_name, cert_type='certificate')
+
+ Retrieve certificates from Windows' system cert store. *store_name* may be
+ one of ``CA``, ``ROOT`` or ``MY``. Windows may provide additional cert
+ stores, too. *cert_type* is either ``certificate`` for X.509 certificates
+ or ``crl`` for X.509 certificate revocation lists.
+
+ The function returns a list of (bytes, encoding_type) tuples. The
+ encoding_type flag can be interpreted with :const:`X509_ASN_ENCODING` or
+ :const:`PKCS_7_ASN_ENCODING`.
+
+ Availability: Windows.
+
+ .. versionadded:: 3.4
Constants
^^^^^^^^^
@@ -598,6 +612,15 @@
.. versionadded:: 3.4
+.. data:: X509_ASN_ENCODING
+ PKCS_7_ASN_ENCODING
+
+ Encoding flags for :func:`enum_cert_store`.
+
+ Availability: Windows.
+
+ .. versionadded:: 3.4
+
SSL Sockets
-----------
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -89,6 +89,7 @@
import textwrap
import re
+import sys
import os
import collections
@@ -139,6 +140,9 @@
_PROTOCOL_NAMES[PROTOCOL_TLSv1_1] = "TLSv1.1"
_PROTOCOL_NAMES[PROTOCOL_TLSv1_2] = "TLSv1.2"
+if sys.platform == "win32":
+ from _ssl import enum_cert_store, X509_ASN_ENCODING, PKCS_7_ASN_ENCODING
+
from socket import getnameinfo as _getnameinfo
from socket import socket, AF_INET, SOCK_STREAM, create_connection
import base64 # for DER-to-PEM translation
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -407,6 +407,29 @@
self.assertEqual(paths.capath, CAPATH)
+ @unittest.skipUnless(sys.platform == "win32", "Windows specific")
+ def test_enum_cert_store(self):
+ self.assertEqual(ssl.X509_ASN_ENCODING, 1)
+ self.assertEqual(ssl.PKCS_7_ASN_ENCODING, 0x00010000)
+
+ self.assertEqual(ssl.enum_cert_store("CA"),
+ ssl.enum_cert_store("CA", "certificate"))
+ ssl.enum_cert_store("CA", "crl")
+ self.assertEqual(ssl.enum_cert_store("ROOT"),
+ ssl.enum_cert_store("ROOT", "certificate"))
+ ssl.enum_cert_store("ROOT", "crl")
+
+ self.assertRaises(TypeError, ssl.enum_cert_store)
+ self.assertRaises(WindowsError, ssl.enum_cert_store, "")
+ self.assertRaises(ValueError, ssl.enum_cert_store, "CA", "wrong")
+
+ ca = ssl.enum_cert_store("CA")
+ self.assertIsInstance(ca, list)
+ self.assertIsInstance(ca[0], tuple)
+ self.assertEqual(len(ca[0]), 2)
+ self.assertIsInstance(ca[0][0], bytes)
+ self.assertIsInstance(ca[0][1], int)
+
class ContextTests(unittest.TestCase):
@skip_if_broken_ubuntu_ssl
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -115,6 +115,8 @@
Library
-------
+- Issue #17134: Add ssl.enum_cert_store() as interface to Windows' cert store.
+
- Issue #18143: Implement ssl.get_default_verify_paths() in order to debug
the default locations for cafile and capath.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2801,7 +2801,129 @@
return NULL;
}
-
+#ifdef _MSC_VER
+PyDoc_STRVAR(PySSL_enum_cert_store_doc,
+"enum_cert_store(store_name, cert_type='certificate') -> []\n\
+\n\
+Retrieve certificates from Windows' cert store. store_name may be one of\n\
+'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\
+cert_type must be either 'certificate' or 'crl'.\n\
+The function returns a list of (bytes, encoding_type) tuples. The\n\
+encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\
+PKCS_7_ASN_ENCODING.");
+
+static PyObject *
+PySSL_enum_cert_store(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = {"store_name", "cert_type", NULL};
+ char *store_name;
+ char *cert_type = "certificate";
+ HCERTSTORE hStore = NULL;
+ PyObject *result = NULL;
+ PyObject *tup = NULL, *cert = NULL, *enc = NULL;
+ int ok = 1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s:enum_cert_store",
+ kwlist, &store_name, &cert_type)) {
+ return NULL;
+ }
+
+ if ((strcmp(cert_type, "certificate") != 0) &&
+ (strcmp(cert_type, "crl") != 0)) {
+ return PyErr_Format(PyExc_ValueError,
+ "cert_type must be 'certificate' or 'crl', "
+ "not %.100s", cert_type);
+ }
+
+ if ((result = PyList_New(0)) == NULL) {
+ return NULL;
+ }
+
+ if ((hStore = CertOpenSystemStore(NULL, store_name)) == NULL) {
+ Py_DECREF(result);
+ return PyErr_SetFromWindowsErr(GetLastError());
+ }
+
+ if (strcmp(cert_type, "certificate") == 0) {
+ PCCERT_CONTEXT pCertCtx = NULL;
+ while (pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) {
+ cert = PyBytes_FromStringAndSize((const char*)pCertCtx->pbCertEncoded,
+ pCertCtx->cbCertEncoded);
+ if (!cert) {
+ ok = 0;
+ break;
+ }
+ if ((enc = PyLong_FromLong(pCertCtx->dwCertEncodingType)) == NULL) {
+ ok = 0;
+ break;
+ }
+ if ((tup = PyTuple_New(2)) == NULL) {
+ ok = 0;
+ break;
+ }
+ PyTuple_SET_ITEM(tup, 0, cert); cert = NULL;
+ PyTuple_SET_ITEM(tup, 1, enc); enc = NULL;
+
+ if (PyList_Append(result, tup) < 0) {
+ ok = 0;
+ break;
+ }
+ Py_CLEAR(tup);
+ }
+ if (pCertCtx) {
+ /* loop ended with an error, need to clean up context manually */
+ CertFreeCertificateContext(pCertCtx);
+ }
+ } else {
+ PCCRL_CONTEXT pCrlCtx = NULL;
+ while (pCrlCtx = CertEnumCRLsInStore(hStore, pCrlCtx)) {
+ cert = PyBytes_FromStringAndSize((const char*)pCrlCtx->pbCrlEncoded,
+ pCrlCtx->cbCrlEncoded);
+ if (!cert) {
+ ok = 0;
+ break;
+ }
+ if ((enc = PyLong_FromLong(pCrlCtx->dwCertEncodingType)) == NULL) {
+ ok = 0;
+ break;
+ }
+ if ((tup = PyTuple_New(2)) == NULL) {
+ ok = 0;
+ break;
+ }
+ PyTuple_SET_ITEM(tup, 0, cert); cert = NULL;
+ PyTuple_SET_ITEM(tup, 1, enc); enc = NULL;
+
+ if (PyList_Append(result, tup) < 0) {
+ ok = 0;
+ break;
+ }
+ Py_CLEAR(tup);
+ }
+ if (pCrlCtx) {
+ /* loop ended with an error, need to clean up context manually */
+ CertFreeCRLContext(pCrlCtx);
+ }
+ }
+
+ /* In error cases cert, enc and tup may not be NULL */
+ Py_XDECREF(cert);
+ Py_XDECREF(enc);
+ Py_XDECREF(tup);
+
+ if (!CertCloseStore(hStore, 0)) {
+ /* This error case might shadow another exception.*/
+ Py_DECREF(result);
+ return PyErr_SetFromWindowsErr(GetLastError());
+ }
+ if (ok) {
+ return result;
+ } else {
+ Py_DECREF(result);
+ return NULL;
+ }
+}
+#endif
/* List of functions exported by this module. */
@@ -2822,6 +2944,10 @@
#endif
{"get_default_verify_paths", (PyCFunction)get_default_verify_paths,
METH_NOARGS, PySSL_get_default_verify_paths_doc},
+#ifdef _MSC_VER
+ {"enum_cert_store", (PyCFunction)PySSL_enum_cert_store,
+ METH_VARARGS | METH_KEYWORDS, PySSL_enum_cert_store_doc},
+#endif
{NULL, NULL} /* Sentinel */
};
@@ -3034,6 +3160,12 @@
PyModule_AddIntConstant(m, "CERT_REQUIRED",
PY_SSL_CERT_REQUIRED);
+#ifdef _MSC_VER
+ /* Windows dwCertEncodingType */
+ PyModule_AddIntMacro(m, X509_ASN_ENCODING);
+ PyModule_AddIntMacro(m, PKCS_7_ASN_ENCODING);
+#endif
+
/* Alert Descriptions from ssl.h */
/* note RESERVED constants no longer intended for use have been removed */
/* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 */
diff --git a/PC/VS9.0/_socket.vcproj b/PC/VS9.0/_socket.vcproj
--- a/PC/VS9.0/_socket.vcproj
+++ b/PC/VS9.0/_socket.vcproj
@@ -54,7 +54,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -115,7 +115,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -176,7 +176,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -238,7 +238,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -299,7 +299,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -361,7 +361,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
TargetMachine="17"
/>
@@ -423,7 +423,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
/>
<Tool
@@ -485,7 +485,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
+ AdditionalDependencies="ws2_32.lib;crypt32.lib"
BaseAddress="0x1e1D0000"
TargetMachine="17"
/>
diff --git a/PCbuild/_ssl.vcxproj b/PCbuild/_ssl.vcxproj
--- a/PCbuild/_ssl.vcxproj
+++ b/PCbuild/_ssl.vcxproj
@@ -158,7 +158,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -173,7 +173,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -185,7 +185,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -200,7 +200,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='PGInstrument|Win32'">
@@ -212,7 +212,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='PGInstrument|x64'">
@@ -227,7 +227,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
@@ -240,7 +240,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out32\libeay32.lib;$(opensslDir)\out32\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='PGUpdate|x64'">
@@ -255,7 +255,7 @@
</Command>
</PreLinkEvent>
<Link>
- <AdditionalDependencies>ws2_32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>ws2_32.lib;crypt32.lib;$(opensslDir)\out64\libeay32.lib;$(opensslDir)\out64\ssleay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list