从OpenSSL-1.0.1r中删除OPENSSL_cleanse

时间:2016-02-28 16:11:33

标签: c++ c xcode linker openssl

我发现OPENSSL_cleanse在我的project中浪费了很多时间。例如,如果它运行25秒,则OPENSSL_cleanse会浪费 3秒。我检查了这个函数的代码,并决定它不会对我做任何非常有用的事情。出于安全考虑,我知道fills memory with garbage data但我并不十分关心它。所以我决定在此函数的任何操作开始之前放置return;

void OPENSSL_cleanse(void *ptr, size_t len)
{
    return;
    // original OpenSSL code goes here
}

我正在使用Mac OS和Xcode。我已经编译了lib并通过/Users/ForceBru/Desktop/openssl脚本的--openssldir选项将其安装在Configure中。我已将其添加到Build Settings->Link Binary With Libraries中的项目中,并在Build Settings->Search Paths->Header Search PathsBuild Settings->Search Paths->Library Search Paths中添加了dirs。

该项目编译良好,但时间分析器仍显示对OPENSSL_cleanse的非常昂贵的调用。

编辑: C标记是因为OpenSSL是用C编写的,C++标记是因为我的代码是用C ++编写的。也许这些信息会有所帮助。

问题是,我做错了什么?如何删除对OPENSSL_cleanse的来电?我认为这与链接有关,因为命令行包含-lcrypto,这意味着这个库实际上可以从任何地方获取(对吗?),而不一定来自/Users/ForceBru/Desktop/openssl

编辑#2:我已编辑了链接器选项,以使用.a中的/Users/ForceBru/Desktop/openssl文件并将其从Build Settings->Link Binary With Libraries中删除。仍然没有效果。

2 个答案:

答案 0 :(得分:0)

事实证明,OpenSSL有很多由位于crypto目录(*cpuid.pl)中的Perl脚本生成的汇编代码。这些脚本为以下体系结构生成汇编代码:alphaarmv4ia64ppcs390xsparc,{{1} }和x86

x86_64运行时,相应的脚本将触发生成make(其中*cpuid.S是前面提到的体系结构之一)。这些文件被编译到库中,似乎覆盖了*中实现的OPENSSL_cleanse

我必须做的只是在crypto/mem_clr.c中将OPENSSL_cleanse的正文更改为ret

x86_64cpuid.pl

答案 1 :(得分:0)

这不是你想要的答案,但它可以帮助你......

  

从OpenSSL-1.0.1r中删除OPENSSL_cleanse ...
  我检查了这个函数的代码,并确定它对我没有做任何有用的事情......

这可能是一个坏主意,但我们需要更多地了解您的威胁模型。归零允许您确定性地从内存中删除敏感材料。

它也是认证和认证(C& A)项目。例如,FIPS 140-2即使在第1级也需要归零。

此外,您无法删除OPENSSL_cleanse 本身,因为OPENSSL_clear_reallocOPENSSL_clear_free和朋友称之为。另请参阅OPENSSL_cleanse手册页。

  

例如,如果它运行25秒,OPENSSL_cleanse浪费了3秒

好的,所以这是一个不同的问题。 OPENSSL_cleanse有点复杂,为了在优化过程中存活,它确实浪费了一些周期。

如果选中Commit 380f18ed5f140e0a,则会在OpenSSL 1.1.0中看到它已更改为以下内容。也许你可以用呢?

diff --git a/crypto/mem_clr.c b/crypto/mem_clr.c
index e6450a1..3389919 100644 (file)
--- a/crypto/mem_clr.c
+++ b/crypto/mem_clr.c
@@ -59,23 +59,16 @@
 #include <string.h>
 #include <openssl/crypto.h>

-extern unsigned char cleanse_ctr;
-unsigned char cleanse_ctr = 0;
+/*
+ * Pointer to memset is volatile so that compiler must de-reference
+ * the pointer and can't assume that it points to any function in
+ * particular (such as memset, which it then might further "optimize")
+ */
+typedef void *(*memset_t)(void *,int,size_t);
+
+static volatile memset_t memset_func = memset;

 void OPENSSL_cleanse(void *ptr, size_t len)
 {
-    unsigned char *p = ptr;
-    size_t loop = len, ctr = cleanse_ctr;
-
-    if (ptr == NULL)
-        return;
-
-    while (loop--) {
-        *(p++) = (unsigned char)ctr;
-        ctr += (17 + ((size_t)p & 0xF));
-    }
-    p = memchr(ptr, (unsigned char)ctr, len);
-    if (p)
-        ctr += (63 + (size_t)p);
-    cleanse_ctr = (unsigned char)ctr;
+    memset_func(ptr, 0, len);
 }

另请参阅OpenSSL的GitHub上的Issue 455: Reimplement non-asm OPENSSL_cleanse()

  

如何删除对OPENSSL_cleanse的调用?

好的,所以这是一个不同的问题。您必须找到所有呼叫者并对每个呼叫者执行某些操作。看起来你需要修改大约185个地方:

$ cd openssl
$ grep -IR _cleanse * | wc -l
     185

而不是:

void OPENSSL_cleanse(void *ptr, size_t len)
{
    return;
    // original OpenSSL code goes here
}

也许您可以删除该功能,然后:

#define OPENSSL_cleanse(x, y)

然后函数调用变成一个在优化过程中消失的宏。从功能更改为宏后,请务必执行make clean

但我不建议这样做。

  

该项目编译得很好,但时间分析器仍显示对OPENSSL_cleanse的相当昂贵的调用。

我的猜测是(1)您在更改OpenSSL库后没有执行make clean,或者(2)您编译并链接到错误版本的OpenSSL库。但我两个都错了。

您可以使用otool -L查看可执行文件的运行时依赖项。确保它是预期的。另请注意,OpenSSL不使用-install_name

在运行可执行文件之前,您可以设置DYLD_LIBRARY_PATH以确保加载了您正在修改的dylib。另请参阅dyld(1)手册页。