如何将 PKCS7_sign 结果转换为 char * 或 std::string

2023-11-25

我尝试编写一个小邮件过滤器来使用 S/MIME 签署邮件。到目前为止,我已经完成了签署邮件的代码。我使用 openssl 中的 demos/smime 代码示例来完成这项工作。不幸的是,这些示例演示了如何将输入消息写入输出文件,但我需要结果作为字符串。

这是我的 Smime 方法:

void Smime::sign() {
    if (!isLoaded())
        return;

    // Null-mailer or unknown
    if (mailFrom.empty())
        return;

    auto *client = util::mlfipriv(ctx);
    bool signedOrEncrypted = false;
    std::vector<std::string> contentType;

    contentType.push_back("multipart/signed");
    contentType.push_back("multipart/encrypted");
    contentType.push_back("application/pkcs7-mime");

    if (client->sessionData.count("Content-Type") == 1) {
        std::string value {client->sessionData["Content-Type"]};
        std::size_t found;

        for (int i=0; i<contentType.size(); i++) {
            found = value.find(contentType.at(i));
            if (found != std::string::npos) {
                signedOrEncrypted = true;
                break;
            }
        }
    }

    if (signedOrEncrypted) {
        const char logmsg[] = "Message already signed or encrypted";
        syslog(LOG_NOTICE, "%s", logmsg);
        return;
    }

    /*
     * TODO:
     * Catch more cases, where an email already could have been encrypted
     * or signed elsewhere.
     */

    mapfile::Map email {mailFrom};

    auto cert = fs::path(email.getSmimeFilename<mapfile::Smime::CERT>());
    auto key = fs::path(email.getSmimeFilename<mapfile::Smime::KEY>());

    if (!fs::exists(cert) && !fs::is_regular(cert))
        return;
    if (!fs::exists(key) && !fs::is_regular(key))
        return;

    // Signing starts here

    BIO *in = nullptr, *out = nullptr, *tbio = nullptr;
    X509 *scert = nullptr;
    EVP_PKEY *skey = nullptr;
    PKCS7 *p7 = nullptr;

    int flags = PKCS7_DETACHED | PKCS7_STREAM;

    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    // S/MIME certificate
    tbio = BIO_new_file(cert.string().c_str(), "r");

    if (!tbio) {
        std::cerr << "Error: BIO_new_file(Cert) failed" << std::endl;
        return;
    }

    scert = PEM_read_bio_X509(tbio, nullptr, 0, nullptr);

    // S/MIME key
    tbio = BIO_new_file(key.string().c_str(), "r");

    if (!tbio) {
        std::cerr << "Error: BIO_new_file(Key) failed" << std::endl;
        return;
    }

    skey = PEM_read_bio_PrivateKey(tbio, nullptr, 0, nullptr);

    if (!scert || !skey) {
        std::cerr << "Error: Neither cert or key was loaded" << std::endl;
        return;
    }

    // Loading mail content from temp file
    in = BIO_new_file(client->getTempFile().c_str(), "r");

    if (!in) {
        std::cerr << "Error: Unable to load content from temp file"
                  << std::endl;
        return;
    }

    // Signing
    p7 = PKCS7_sign(scert, skey, nullptr, in, flags);

    if (!p7) {
        std::cerr << "Error: Message could not be signed" << std::endl;
        return;
    }

    // Cleanup
    PKCS7_free(p7);
    X509_free(scert);
    EVP_PKEY_free(skey);
    BIO_free(in);
    BIO_free(out);
    BIO_free(tbio);

    smimeSigned = true;
}

由于 openssl 有超过 1600 个手册页,我不知道在哪里寻找信息。

我很想使用“p7”并将其写入一个简单的 std::string (或 char *,如果需要)。我编写的 milter 应用程序将拾取该字符串并执行更改主体(尚未编写,但这是我的想法)。

有人可以向我指出例程/手册页或者有可以帮助我的代码示例吗?

提前致谢


我很想使用“p7”并将其写入一个简单的 std::string (或 char *,如果需要)。我编写的 milter 应用程序将拾取该字符串并执行更改主体(尚未编写,但这是我的想法)。

我不相信你可以把它放在char*因为可能有一个嵌入的NULL,这会截断结果。

Use a std::string以及 (1)i2d_PKCS7_bio对于 ASN.1/DER 或 (2)PEM_write_bio_PKCS7对于质子交换膜。这个想法是你像往常一样使用该库,将输出写入MEM_BIO然后使用获取生物的内容BUF_MEM. The BUF_MEM保存一个指向数据及其长度的指针。就像是...

using BIO_MEM_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
using BIO_MEM_BUF_ptr = std::unique_ptr<BUF_MEM, decltype(&::BIO_free)>;

BIO_MEM_ptr bio(BIO_new(BIO_s_mem()), ::BIO_free);
int ret = i2d_PKCS7_bio(bio, p7);
ASSERT(ret == 1);

BIO_MEM_BUF_ptr buff;
BIO_get_mem_ptr(bio.get(), &buff.get());

const BUF_MEM& t = *buff.get();
std::string result((t.data ? t.data : ""), (t.data ? t.length : 0));

If你用PEM_write_bio_PKCS7 and a char*,那么 PEM 编码将缺少终止符NULL。请务必考虑到它,因为它不是 C 字符串。另请参阅生成随机 n 字节 Base64 字符串后的不可打印字符,其中讨论了如何在不进行编码的情况下写入 NULL。


由于 openssl 有超过 1600 个手册页,我不知道在哪里寻找信息......

查看子命令的源代码。它向您展示了库如何使用 API 进行操作。例如,当您使用openssl pkcs7,它使用pkcs7 app.

$ cd <openssl src dir>
$ cd apps
$ ls *.c
app_rand.c  dsaparam.c  openssl.c   rehash.c    speed.c
apps.c      ec.c        opt.c       req.c       spkac.c
asn1pars.c  ecparam.c   passwd.c    rsa.c       srp.c
ca.c        enc.c       pkcs12.c    rsautl.c    ts.c
ciphers.c   engine.c    pkcs7.c     s_cb.c      verify.c
cms.c       errstr.c    pkcs8.c     s_client.c  version.c
crl.c       gendsa.c    pkey.c      s_server.c  vms_decc_init.c
crl2p7.c    genpkey.c   pkeyparam.c s_socket.c  x509.c
dgst.c      genrsa.c    pkeyutl.c   s_time.c
dhparam.c   nseq.c      prime.c     sess_id.c
dsa.c       ocsp.c      rand.c      smime.c

Using unique_ptr使用 dtor 函数可确保自动清理对象,并有助于保持代码干净。每当 OpenSSL 与 C++ 交叉路径时我都会尝试使用它(请参阅如何使用openssl生成RSA私钥另一个例子)。

以下是我的一个使用 OpenSSL 的 C++ 项目中的一些内容:

using EC_KEY_ptr = std::unique_ptr<EC_KEY, decltype(&::EC_KEY_free)>;
using EC_GROUP_ptr = std::unique_ptr<EC_GROUP, decltype(&::EC_GROUP_free)>;
using EC_POINT_ptr = std::unique_ptr<EC_POINT, decltype(&::EC_POINT_free)>;

using DH_ptr = std::unique_ptr<DH, decltype(&::DH_free)>;

using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;

using DSA_ptr = std::unique_ptr<DSA, decltype(&::DSA_free)>;

using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;

using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;

using FILE_ptr = std::unique_ptr<FILE, decltype(&::fclose)>;

using BIO_MEM_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
using BIO_FILE_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;

using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_destroy)>;

using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
using ASN1_INTEGER_ptr = std::unique_ptr<ASN1_INTEGER, decltype(&::ASN1_INTEGER_free)>;
using ASN1_TIME_ptr = std::unique_ptr<ASN1_TIME, decltype(&::ASN1_TIME_free)>;
using X509_EXTENSION_ptr = std::unique_ptr<X509_EXTENSION, decltype(&::X509_EXTENSION_free)>;

using X509_NAME_ptr = std::unique_ptr<X509_NAME, decltype(&::X509_NAME_free)>;
using X509_NAME_ENTRY_ptr = std::unique_ptr<X509_NAME_ENTRY, decltype(&::X509_NAME_ENTRY_free)>;

using X509_STORE_ptr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
using X509_LOOKUP_ptr = std::unique_ptr<X509_LOOKUP, decltype(&::X509_LOOKUP_free)>;
using X509_STORE_CTX_ptr = std::unique_ptr<X509_STORE_CTX, decltype(&::X509_STORE_CTX_free)>;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 PKCS7_sign 结果转换为 char * 或 std::string 的相关文章

  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 获取按下的按钮的返回值

    我有一个在特定事件中弹出的表单 它从数组中提取按钮并将标签值设置为特定值 因此 如果您要按下或单击此按钮 该函数应返回标签值 我怎样才能做到这一点 我如何知道点击了哪个按钮 此时代码返回 DialogResult 但我想从函数返回 Tag
  • 将数组向左或向右旋转一定数量的位置,复杂度为 o(n)

    我想编写一个程序 根据用户的输入 正 gt 负 include
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • 使用 System.Text.Json 即时格式化 JSON 流

    我有一个未缩进的 Json 字符串 例如 hash 123 id 456 我想缩进字符串并将其序列化为 JSON 文件 天真地 我可以使用缩进字符串Newtonsoft如下 using Newtonsoft Json Linq JToken
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • clang 实例化后静态成员初始化

    这样的代码可以用 GCC 编译 但 clang 3 5 失败 include
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 防止索引超出范围错误

    我想编写对某些条件的检查 而不必使用 try catch 并且我想避免出现 Index Out of Range 错误的可能性 if array Element 0 Object Length gt 0 array Element 1 Ob
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐

  • 如何防止 Firebase Web 应用程序的客户端控制台遭到黑客攻击?

    我突然意识到 有了如此多的客户端逻辑 恶意用户可以通过在任何浏览器中使用控制台来欺骗 覆盖或游戏 Firebase 应用程序 例如 我可以输入 flag click 并用三笔标记我的应用程序上的每个帖子都不存在 我写的任何防御逻辑都将提供给
  • 为什么谷歌字体粗细不起作用?

    我正在努力改变h1 to font weight 300 除非我这样做 h1 font weight 300 什么都没发生 因此 为了测试其他文本元素的字体粗细 我设置了整个封装容器 container fluid to a font we
  • 致命异常:android.view.WindowManager$BadTokenException 无法添加窗口——令牌无效;您的活动正在运行吗?

    我知道这个问题已经讨论过好几次了 但相信我 我从来没有得到任何有效的答案 在我的主要活动中 我使用了几个对话框来通知用户某些操作 但我在小米设备上大多数情况下 特别是 96 都会遇到此特定错误 Fatal Exception android
  • 以编程方式使用 Eureka 客户端问题 - DiscoveryClient 已完成关闭

    我已经创建了具有复制功能的 Eureka 服务器现在尝试启动客户端 当我尝试启动时spring microservices eureka client 我收到以下错误 使用 Spring Boot 版本2 1 1 RELEASE 启动版本也
  • Jquery加载https url

    我有这个问题 在外部网站中我有一个像这样的脚本 div div example com 采用 https 允许 http 和 https 在脚本 widget js 的服务器中 我有 idtest load https example co
  • 使用 Typescript 通过 Webpack 动态加载模块

    我正在尝试构建一个支持插件的 Web 应用程序 环境是 Angular 2 到目前为止 Typescript 2 1 和 Webpack 2 我有一些扩展点 插槽 插件可以在其中绘制内容 基本上我有一个组件 它能够托管运行时已知的其他一些组
  • 脚本由 Bash 执行时产生的结果与由 cron 执行时产生的结果不同

    请考虑以下 crontab root SHELL bin bash 0 3 var maintenance raid sh 和 bash 脚本 var maintenance raid sh bin bash echo n Checking
  • 了解 Python Pickle 不安全性

    Python 文档中指出pickle不安全 不应解析不受信任的用户输入 如果你研究这个 几乎所有的例子都证明了这一点system 通过呼叫os system 我不清楚的是如何os system没有被正确解释os正在导入模块 gt gt gt
  • 如何获取 win32 API 中所有屏幕的尺寸(RECT)?

    我正在为测试团队编写一份应用程序 该应用程序的作用是让您截取屏幕任何部分的屏幕截图 然后将其连同注释一起上传到测试团队服务器 截屏涉及选择屏幕上要截屏的区域 为此 我创建了一个半透明窗口并将其覆盖在整个屏幕上 我目前正在使用GetDeskt
  • 在 Google 地图上放置图钉

    我需要将用户重定向到 Google 地图页面并在定义的位置上放置一些图钉 问题是您可以通过简单的请求轻松地将地图集中在某个点上 但是对于这样的要求如何设置pin呢 您可以使用 我的地图 来执行此操作 创建或打开地图 单击编辑进入编辑模式 单
  • 获取作为给定项目实例的所有维基数据项目

    维基数据有一个项目叫做智能手机型号 我想获取它的所有实例 问题 如何使用实时服务器以编程方式获取实例的标识符 最好不包括出现在 WhatLinksHere 但位于 Wikidata 命名空间而不是主命名空间中的误报 您的问题指定了 Medi
  • 在 JavaScript 中获取下周的某一天的日期

    根据今天的日期 new Date 我想在 javascript 中获取下周四晚上 7 点的日期 例如 如果今天的日期是 Mon Apr 24 2017 13 00 00 GMT 我正在寻找结果 Thu Apr 27 2017 19 00 0
  • 隐藏 Samsung Galaxy 设备上的“不支持 NFC 标签类型”错误

    我正在开发一款仅扫描 MIFARE Classic 卡的 UID 的应用程序 以方便考勤登记 我已经让它工作了 然而 每次我在 Galaxy S4 上扫描卡时 都会收到一条提示 不支持 NFC 标签类型 我想在应用程序打开时阻止或隐藏该消息
  • python - 从浮点数中删除所有小数

    如何从浮点数中删除所有小数位 a 100 0 我希望它变成 100 I tried str a rstrip 0 但它刚刚返回1 将其转换为怎么样int gt gt gt int a 100 为了完整起见 有很多方法可以从十进制数的字符串表
  • gdb 终止于信号?,未知信号

    我只是尝试在 Mac OSX 版本 10 12 上使用 gdb 调试代码 但在 gdb 中启动程序时总是遇到此未知错误 我在安装后对 gdb 进行了代码签名 并使用 g 标志编译了我的代码 这就是正在发生的事情 computer hello
  • 如何使用 refs 访问/覆盖元素的 className?

    我有一个文本和一个按钮 我想要实现的是这样的 如果我单击按钮 文本将被隐藏 我想在不使用的情况下实现这一目标state class Test extends Component constructor props codes hide gt
  • app.config 中的用户范围与应用程序范围

    app config 中的用户范围和应用程序范围有什么区别 用户范围设置用于存储特定于每个用户的值 而应用程序范围设置用于所有用户 看看这个article
  • 列表 SwiftUI 中的每行是否可以有多个 NavigationLink?

    我无法在列表的同一行中使用多个 NavigationLink 看起来导航堆栈完全混乱了 因为你点击一次 它就会进入多个视图并不稳定地返回 在 TestList 中 我尝试在部分中添加单独的 NavigationLinks 并且尝试将 Nav
  • 网络浏览器键盘快捷键

    我有一个显示一些 HTML 的 WebBrowser 控件 我希望用户能够复制整个文档 但不能执行任何其他操作 我已经设置了IsWebBrowserContextMenuEnabled and WebBrowserShortcutsEnab
  • 如何将 PKCS7_sign 结果转换为 char * 或 std::string

    我尝试编写一个小邮件过滤器来使用 S MIME 签署邮件 到目前为止 我已经完成了签署邮件的代码 我使用 openssl 中的 demos smime 代码示例来完成这项工作 不幸的是 这些示例演示了如何将输入消息写入输出文件 但我需要结果