An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
 
# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1409233289 14400
# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5
# Parent  97081a80f487841d81aeed55d398a1dba1faca00
PEP 466: backport hashlib algorithm constants (closes #21307)
 
diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
--- a/Doc/library/hashlib.rst
+++ b/Doc/library/hashlib.rst
@@ -88,6 +88,24 @@ This module provides the following const
 
    .. versionadded:: 2.7
 
+.. data:: algorithms_guaranteed
+
+   A set containing the names of the hash algorithms guaranteed to be supported
+   by this module on all platforms.
+
+   .. versionadded:: 2.7.9
+
+.. data:: algorithms_available
+
+   A set containing the names of the hash algorithms that are available in the
+   running Python interpreter.  These names will be recognized when passed to
+   :func:`new`.  :attr:`algorithms_guaranteed` will always be a subset.  The
+   same algorithm may appear multiple times in this set under different names
+   (thanks to OpenSSL).
+
+   .. versionadded:: 2.7.9
+
+
 The following values are provided as constant attributes of the hash objects
 returned by the constructors:
 
diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py
--- Python-2.7.5/Lib/hashlib.py.hash    2015-03-04 17:05:57.496598686 +0100
+++ Python-2.7.5/Lib/hashlib.py    2015-03-04 17:11:34.872739103 +0100
@@ -18,8 +18,9 @@ than using new():
 
 md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
 
-More algorithms may be available on your platform but the above are
-guaranteed to exist.
+More algorithms may be available on your platform but the above are guaranteed
+to exist.  See the algorithms_guaranteed and algorithms_available attributes
+to find out what algorithm names can be passed to new().
 
 NOTE: If you want the adler32 or crc32 hash functions they are available in
 the zlib module.
@@ -75,9 +76,14 @@ More condensed:
 # always available algorithm is added.
 __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
 
+algorithms_guaranteed = set(__always_supported)
+algorithms_available = set(__always_supported)
+
 algorithms = __always_supported
 
-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
+__all__ = __always_supported + ('new', 'algorithms_guaranteed',
+                                'algorithms_available', 'algorithms',
+                                'pbkdf2_hmac')
 
 
 def __get_openssl_constructor(name):
@@ -110,6 +116,8 @@ try:
     import _hashlib
     new = __hash_new
     __get_hash = __get_openssl_constructor
+    algorithms_available = algorithms_available.union(
+        _hashlib.openssl_md_meth_names)
 except ImportError:
     # We don't build the legacy modules
     raise
diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c
--- Python-2.7.5/Modules/_hashopenssl.c.hash    2015-03-04 17:06:18.246791837 +0100
+++ Python-2.7.5/Modules/_hashopenssl.c    2015-03-04 17:16:17.696369000 +0100
@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar
 
 #endif
 
+/* State for our callback function so that it can accumulate a result. */
+typedef struct _internal_name_mapper_state {
+    PyObject *set;
+    int error;
+} _InternalNameMapperState;
+
+
+/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
+static void
+_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
+{
+    _InternalNameMapperState *state = (_InternalNameMapperState *)arg;
+    PyObject *py_name;
+
+    assert(state != NULL);
+    if (openssl_obj_name == NULL)
+        return;
+    /* Ignore aliased names, they pollute the list and OpenSSL appears to
+     * have a its own definition of alias as the resulting list still
+     * contains duplicate and alternate names for several algorithms.     */
+    if (openssl_obj_name->alias)
+        return;
+
+    py_name = PyString_FromString(openssl_obj_name->name);
+    if (py_name == NULL) {
+        state->error = 1;
+    } else {
+        if (PySet_Add(state->set, py_name) != 0) {
+            state->error = 1;
+        }
+        Py_DECREF(py_name);
+    }
+}
+
+
+/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
+static PyObject*
+generate_hash_name_list(void)
+{
+    _InternalNameMapperState state;
+    state.set = PyFrozenSet_New(NULL);
+    if (state.set == NULL)
+        return NULL;
+    state.error = 0;
+
+    OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
+
+    if (state.error) {
+        Py_DECREF(state.set);
+        return NULL;
+    }
+    return state.set;
+}
+
+
 /*
  *  This macro and function generates a family of constructor function
  *  definitions for specific hash algorithms.  These constructors are much
@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[
 PyMODINIT_FUNC
 init_hashlib(void)
 {
-    PyObject *m;
+    PyObject *m, *openssl_md_meth_names;
 
     SSL_load_error_strings();
     SSL_library_init();
-    OpenSSL_add_all_digests();
+    ERR_load_crypto_strings();
 
     Py_TYPE(&EVPtype) = &PyType_Type;
     if (PyType_Ready(&EVPtype) < 0)
@@ -938,6 +993,14 @@ init_hashlib(void)
     if (m == NULL)
         return;
 
+    openssl_md_meth_names = generate_hash_name_list();
+    if (openssl_md_meth_names == NULL) {
+        return;
+    }
+    if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
+        return;
+    }
+
 #if HASH_OBJ_CONSTRUCTOR
     Py_INCREF(&EVPtype);
     PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py
--- Python-2.7.5/Lib/test/test_hashlib.py.hash    2015-03-04 18:04:57.823553474 +0100
+++ Python-2.7.5/Lib/test/test_hashlib.py    2015-03-04 18:06:39.395499123 +0100
@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase)
             tuple([_algo for _algo in self.supported_hash_names if
                                                 _algo.islower()]))
 
+    def test_algorithms_guaranteed(self):
+        self.assertEqual(hashlib.algorithms_guaranteed,
+            set(_algo for _algo in self.supported_hash_names
+                  if _algo.islower()))
+
+    def test_algorithms_available(self):
+        self.assertTrue(set(hashlib.algorithms_guaranteed).
+                            issubset(hashlib.algorithms_available))
+
     def test_unknown_hash(self):
         self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
         self.assertRaises(TypeError, hashlib.new, 1)