Hus*_*bar 5 python ssl fips python-3.x
我正在尝试在 Python 的 ssl 模块中实现 FIPS_mode 和 FIPS_mode_set 函数,因为默认情况下它们不存在。由于各种使用原因,Python 3.4的补丁已经提交并被拒绝。
使用该补丁作为灵感,我进行了一些修改并在ssl.py 中添加了以下代码:
try:
from _ssl import FIPS_mode, FIPS_mode_set
except ImportError:
pass
Run Code Online (Sandbox Code Playgroud)
_ssl.c 中的以下代码:
#define EXPORT_FIPSMODE_FUNCS
#ifdef EXPORT_FIPSMODE_FUNCS
static PyObject *
_ssl_FIPS_mode_impl(PyObject *module) {
return PyLong_FromLong(FIPS_mode());
}
static PyObject *
_ssl_FIPS_mode_set_impl(PyObject *module, int n) {
if (FIPS_mode_set(n) == 0) {
_setSSLError(ERR_error_string(ERR_get_error(), NULL) , 0, __FILE__, __LINE__);
return NULL;
}
Py_RETURN_NONE;
}
#endif //EXPORT_FIPSMODE_FUNCS
/* List of functions exported by this module. */
static PyMethodDef PySSL_methods[] = {
_SSL__TEST_DECODE_CERT_METHODDEF
_SSL_RAND_ADD_METHODDEF
_SSL_RAND_BYTES_METHODDEF
_SSL_RAND_PSEUDO_BYTES_METHODDEF
_SSL_RAND_EGD_METHODDEF
_SSL_RAND_STATUS_METHODDEF
_SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF
_SSL_ENUM_CERTIFICATES_METHODDEF
_SSL_ENUM_CRLS_METHODDEF
_SSL_TXT2OBJ_METHODDEF
_SSL_NID2OBJ_METHODDEF
_SSL_FIPS_MODE_SET_METHODDEF
_SSL_FIPS_MODE_METHODDEF
{NULL, NULL} /* Sentinel */
};
Run Code Online (Sandbox Code Playgroud)
然而,这会引发以下错误:
./Modules/_ssl.c:5060:5: error: '_SSL_FIPS_MODE_SET_METHODDEF' undeclared here (not in a function)
_SSL_FIPS_MODE_SET_METHODDEF
./Modules/_ssl.c:5061:5: error: expected '}' before '_SSL_FIPS_MODE_METHODDEF'
_SSL_FIPS_MODE_METHODDEF
./Modules/_ssl.c:4641:1: warning: '_ssl_FIPS_mode_impl' defined but not used [-Wunused-function] _ssl_FIPS_mode_impl(PyObject
*module) {
./Modules/_ssl.c:4646:1: warning: '_ssl_FIPS_mode_set_impl' defined but not used [-Wunused-function]
_ssl_FIPS_mode_set_impl(PyObject *module, int n) { ^
Run Code Online (Sandbox Code Playgroud)
我很确定我在这里遗漏了一些非常微不足道的东西,但我似乎无法弄清楚到底是什么。任何帮助,将不胜感激!谢谢!
更新:
对@CristiFati 的大喊大叫,他指出我缺少需要定义的宏,我能够解决这个问题。如果其他人需要在 Python 3.6 中实现 FIPS 模式,请添加以下代码:
_ssl.c:
static PyObject *
_ssl_FIPS_mode_impl(PyObject *module) {
return PyLong_FromLong(FIPS_mode());
}
static PyObject *
_ssl_FIPS_mode_set_impl(PyObject *module, int n) {
if (FIPS_mode_set(n) == 0) {
_setSSLError(ERR_error_string(ERR_get_error(), NULL) , 0, __FILE__, __LINE__);
return NULL;
}
Py_RETURN_NONE;
}
static PyMethodDef PySSL_methods[] = {
_SSL__TEST_DECODE_CERT_METHODDEF
_SSL_RAND_ADD_METHODDEF
_SSL_RAND_BYTES_METHODDEF
_SSL_RAND_PSEUDO_BYTES_METHODDEF
_SSL_RAND_EGD_METHODDEF
_SSL_RAND_STATUS_METHODDEF
_SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF
_SSL_ENUM_CERTIFICATES_METHODDEF
_SSL_ENUM_CRLS_METHODDEF
_SSL_TXT2OBJ_METHODDEF
_SSL_NID2OBJ_METHODDEF
_SSL_FIPS_MODE_METHODDEF
_SSL_FIPS_MODE_SET_METHODDEF
{NULL, NULL} /* Sentinel */
};
Run Code Online (Sandbox Code Playgroud)
_ssl.ch:
PyDoc_STRVAR(_ssl_FIPS_mode__doc__,
"FIPS Mode");
#define _SSL_FIPS_MODE_METHODDEF \
{"FIPS_mode", (PyCFunction)_ssl_FIPS_mode, METH_NOARGS, _ssl_FIPS_mode__doc__},
static PyObject *
_ssl_FIPS_mode_impl(PyObject *module);
static PyObject *
_ssl_FIPS_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
{
return _ssl_FIPS_mode_impl(module);
}
PyDoc_STRVAR(_ssl_FIPS_mode_set_doc__,
"FIPS Mode Set");
#define _SSL_FIPS_MODE_SET_METHODDEF \
{"FIPS_mode_set", (PyCFunction)_ssl_FIPS_mode_set, METH_O, _ssl_FIPS_mode_set_doc__},
static PyObject *
_ssl_FIPS_mode_set_impl(PyObject *module, int n);
static PyObject *
_ssl_FIPS_mode_set(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
int n;
if (!PyArg_Parse(arg, "i:FIPS_mode_set", &n)) {
goto exit;
}
return_value = _ssl_FIPS_mode_set_impl(module, n);
exit:
return return_value;
}
Run Code Online (Sandbox Code Playgroud)
ssl.py:
try:
from _ssl import FIPS_mode, FIPS_mode_set
print('successful import')
except ImportError as e:
print('error in importing')
print(e)
Run Code Online (Sandbox Code Playgroud)
查看源代码,我注意到自Python 3.5以来,与我使用的3.4版本相比,${PYTHON_SRC_DIR}/Modules/_ssl.c结构发生了变化(“有点”结构化并且还包含生成的代码)将补丁提交给([Python.Bugs]: FIPS_mode() 和 FIPS_mode_set() 函数在 Python (ssl))。基本上,PySSL_methods数组中的每个条目不再是现场定义的,而是通过预处理器宏间接定义的。您按照新标准行事,但忘记定义宏。
为了解决问题:
为PyMethodDef条目(内部 #ifdef EXPORT_FIPSMODE_FUNCS)定义 2 个宏:
// ...
}
#define _SSL_FIPS_MODE_METHODDEF \
{"FIPS_mode", (PyCFunction)_ssl_FIPS_mode_impl, METH_NOARGS, NULL},
#define _SSL_FIPS_MODE_SET_METHODDEF \
{"FIPS_mode_set", (PyCFunction)_ssl_FIPS_mode_set_impl, METH_O, NULL},
#endif // EXPORT_FIPSMODE_FUNCS
// ...
Run Code Online (Sandbox Code Playgroud)
在定义PySSL_methods时,通过#ifdef子句(类似于定义它们的位置)“保护”新宏(这样,如果未定义 EXPORT_FIPSMODE_FUNCS宏,则不会出现编译错误):
// ...
_SSL_NID2OBJ_METHODDEF
#ifdef EXPORT_FIPSMODE_FUNCS
_SSL_FIPS_MODE_METHODDEF
_SSL_FIPS_MODE_SET_METHODDEF
#endif // EXPORT_FIPSMODE_FUNCS
{NULL, NULL} /* Sentinel */
// ...
Run Code Online (Sandbox Code Playgroud)
注意事项:
help()这两个函数中的任何一个时。如果出现段错误,请从补丁中复制定义或使用PyDoc_STRVAR定义一些虚拟字符串(当然还需要重新编译)Python-3.6.4-ssl_fips.diff:
--- Python-3.6.4/Modules/_ssl.c.orig 2018-07-27 19:10:06.131999999 +0300
+++ Python-3.6.4/Modules/_ssl.c 2018-07-27 20:32:15.531999999 +0300
@@ -4789,6 +4789,46 @@
return result;
}
+#if defined(EXPORT_FIPSMODE_FUNCS)
+
+unsigned char _fips_table_sig[0x0C] = {0x21, 0x7A, 0x65, 0x6C, 0x75, 0x72, 0x20, 0x49, 0x54, 0x41, 0x46, 0x00};
+
+/*[clinic input]
+_ssl.FIPS_mode
+
+Return 1 (!=0) if FIPS mode is enabled, 0 otherwise.
+[clinic start generated code]*/
+
+static PyObject *
+_ssl_FIPS_mode_impl(PyObject *module)
+/*[clinic end generated code: output=89f5a88ec715a291 input=52e4e5fdd1f555c7]*/
+{
+ return PyLong_FromLong(FIPS_mode());
+}
+
+/*[clinic input]
+_ssl.FIPS_mode_set
+ mode: int
+ /
+
+Try to set the FIPS mode to 'mode' (int).
+
+Return nothing. Raise SSLError when enabling FIPS mode fails.
+[clinic start generated code]*/
+
+static PyObject *
+_ssl_FIPS_mode_set_impl(PyObject *module, int mode)
+/*[clinic end generated code: output=70e3e9f3bb4fce65 input=899c21a986720235]*/
+{
+if (FIPS_mode_set(mode) == 0) {
+ _setSSLError(ERR_error_string(ERR_get_error(), NULL), 0, __FILE__, __LINE__);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+#endif // EXPORT_FIPSMODE_FUNCS
+
#ifdef _MSC_VER
static PyObject*
@@ -5055,6 +5095,8 @@
_SSL_ENUM_CRLS_METHODDEF
_SSL_TXT2OBJ_METHODDEF
_SSL_NID2OBJ_METHODDEF
+ _SSL_FIPS_MODE_METHODDEF
+ _SSL_FIPS_MODE_SET_METHODDEF
{NULL, NULL} /* Sentinel */
};
--- Python-3.6.4/Modules/clinic/_ssl.c.h.orig 2018-07-27 19:10:48.067999999 +0300
+++ Python-3.6.4/Modules/clinic/_ssl.c.h 2018-07-27 20:31:04.507999999 +0300
@@ -1062,6 +1062,61 @@
return return_value;
}
+#if defined(EXPORT_FIPSMODE_FUNCS)
+
+PyDoc_STRVAR(_ssl_FIPS_mode__doc__,
+"FIPS_mode($module, /)\n"
+"--\n"
+"\n"
+"Return 1 (!=0) if FIPS mode is enabled, 0 otherwise.");
+
+#define _SSL_FIPS_MODE_METHODDEF \
+ {"FIPS_mode", (PyCFunction)_ssl_FIPS_mode, METH_NOARGS, _ssl_FIPS_mode__doc__},
+
+static PyObject *
+_ssl_FIPS_mode_impl(PyObject *module);
+
+static PyObject *
+_ssl_FIPS_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return _ssl_FIPS_mode_impl(module);
+}
+
+#endif /* defined(EXPORT_FIPSMODE_FUNCS) */
+
+#if defined(EXPORT_FIPSMODE_FUNCS)
+
+PyDoc_STRVAR(_ssl_FIPS_mode_set__doc__,
+"FIPS_mode_set($module, mode, /)\n"
+"--\n"
+"\n"
+"Try to set the FIPS mode to \'mode\' (int).\n"
+"\n"
+"Return nothing. Raise SSLError when enabling FIPS mode fails.");
+
+#define _SSL_FIPS_MODE_SET_METHODDEF \
+ {"FIPS_mode_set", (PyCFunction)_ssl_FIPS_mode_set, METH_O, _ssl_FIPS_mode_set__doc__},
+
+static PyObject *
+_ssl_FIPS_mode_set_impl(PyObject *module, int mode);
+
+static PyObject *
+_ssl_FIPS_mode_set(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int mode;
+
+ if (!PyArg_Parse(arg, "i:FIPS_mode_set", &mode)) {
+ goto exit;
+ }
+ return_value = _ssl_FIPS_mode_set_impl(module, mode);
+
+exit:
+ return return_value;
+}
+
+#endif /* defined(EXPORT_FIPSMODE_FUNCS) */
+
#if defined(_MSC_VER)
PyDoc_STRVAR(_ssl_enum_certificates__doc__,
@@ -1161,6 +1216,14 @@
#define _SSL_RAND_EGD_METHODDEF
#endif /* !defined(_SSL_RAND_EGD_METHODDEF) */
+#ifndef _SSL_FIPS_MODE_METHODDEF
+ #define _SSL_FIPS_MODE_METHODDEF
+#endif /* !defined(_SSL_FIPS_MODE_METHODDEF) */
+
+#ifndef _SSL_FIPS_MODE_SET_METHODDEF
+ #define _SSL_FIPS_MODE_SET_METHODDEF
+#endif /* !defined(_SSL_FIPS_MODE_SET_METHODDEF) */
+
#ifndef _SSL_ENUM_CERTIFICATES_METHODDEF
#define _SSL_ENUM_CERTIFICATES_METHODDEF
#endif /* !defined(_SSL_ENUM_CERTIFICATES_METHODDEF) */
@@ -1168,4 +1231,4 @@
#ifndef _SSL_ENUM_CRLS_METHODDEF
#define _SSL_ENUM_CRLS_METHODDEF
#endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
-/*[clinic end generated code: output=a8b184655068c238 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=94d0ec4213d44124 input=a9049054013a1b77]*/
--- Python-3.6.4/Lib/ssl.py.orig 2018-07-27 19:10:29.827999999 +0300
+++ Python-3.6.4/Lib/ssl.py 2018-03-28 23:30:35.065667344 +0300
@@ -114,6 +114,11 @@
# LibreSSL does not provide RAND_egd
pass
+try:
+ from _ssl import FIPS_mode, FIPS_mode_set
+except ImportError:
+ # Compiled without FIPS functions support
+ pass
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
from _ssl import _OPENSSL_API_VERSION
--- Python-3.6.4/setup.py.orig 2018-07-27 19:09:33.763999999 +0300
+++ Python-3.6.4/setup.py 2018-03-28 23:30:35.061667315 +0300
@@ -862,6 +862,7 @@
ssl_libs is not None):
exts.append( Extension('_ssl', ['_ssl.c'],
include_dirs = ssl_incs,
+ define_macros = [("EXPORT_FIPSMODE_FUNCS", None)],
library_dirs = ssl_libs,
libraries = ['ssl', 'crypto'],
depends = ['socketmodule.h']), )
Run Code Online (Sandbox Code Playgroud)
注意事项:
这是一个差异(注意它在${PYTHON_SRC_DIR} 之外)。请参阅[SO]:从 PyCharm 社区版中的鼠标右键单击上下文菜单运行/调试 Django 应用程序的单元测试?(@CristiFati 的回答)(Patching utrunner部分)关于如何在Win上应用补丁(基本上,以一个“+”号开头的每一行都进入,以一个“-”号开头的每一行都退出)。我正在使用Cygwin,顺便说一句
源基线为v3.6.4(如文件名所指)
修改了4个文件:
我还测试了更改(有一次我使用了我为[SO]构建的OpenSSL版本:如何为用 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式?(@CristiFati 的回答))
输出:
Run Code Online (Sandbox Code Playgroud)[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049493537]> LD_LIBRARY_PATH=./py364-nofips/lib ./py364-nofips/bin/python3 -c "import ssl;print(ssl.FIPS_mode())" Traceback (most recent call last): File "<string>", line 1, in <module> AttributeError: module 'ssl' has no attribute 'FIPS_mode' [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049493537]> LD_LIBRARY_PATH=py364-fips/lib py364-fips/bin/python3 -c "import ssl;print(ssl.FIPS_mode(), ssl.FIPS_mode_set(0), ssl.FIPS_mode());print(ssl.FIPS_mode_set(1), ssl.FIPS_mode())" 0 None 0 Traceback (most recent call last): File "<string>", line 1, in <module> ssl.SSLError: error:0F06D065:common libcrypto routines:FIPS_mode_set:fips mode not supported (_ssl.c:4822) [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049493537]> LD_LIBRARY_PATH=py364-fips/lib:../q049320993/ssl/build/lib py364-fips/bin/python3 -c "import ssl;print(ssl.FIPS_mode(), ssl.FIPS_mode_set(0), ssl.FIPS_mode());print(ssl.FIPS_mode_set(1), ssl.FIPS_mode())" 0 None 0 None 1
还可以查看[SO]: OpenSSL FIPS_mode_set not working in Python cryptography library (@CristiFati's answer)。
| 归档时间: |
|
| 查看次数: |
4329 次 |
| 最近记录: |