为什么 OpenSSL 给我一个“调用了不应调用的函数”错误?

2024-04-27

我正在努力向我的服务器程序添加 OpenSSL 支持,通常它运行得很好,但我遇到了一个问题。

首先,一些背景知识:服务器是单线程的,使用非阻塞 I/O 和 select() 循环来同时处理多个客户端。服务器链接到 libssl.0.9.8.dylib 和 lib crypto.0.9.8.dylib (即 MacOS/X 10.8.5 在 /usr/lib 中提供的库)。客户端服务器协议是专有的全双工消息传递协议;也就是说,客户端和服务器都可以随时发送和接收数据,并且客户端 服务器 TCP 连接无限期地保持连接(即,直到客户端或服务器决定断开连接)。

问题是这样的:我的客户端可以连接到服务器,并且发送和接收数据工作正常(现在我已经整理出了 SSL_ERROR_WANT_WRITE 和 SSL_ERROR_WANT_READ 逻辑)......但是如果服务器accept()是一个新的客户端连接while其他客户端正在发送或接收数据,SSL 层似乎已损坏。特别是,在服务器运行 SetupSSL() 例程(如下所示)以设置新接受的套接字后,一个或多个其他(预先存在的)客户端套接字上的 SSL_read() 将立即返回 -1,并且ERR_print_errors_fp(stderr) 给出以下输出:

SSL_read() ERROR:  5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248:

第一次出现此错误后,服务器基本上停止工作。数据移动停止,如果我尝试连接另一个客户端,我经常会收到此错误:

SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578: 

在我的测试场景中,这种情况发生的概率约为 25%。如果我确保在新客户端连接时我预先存在的客户端连接处于空闲状态(没有发送或接收数据),则这种情况永远不会发生。有谁知道这里可能出了什么问题?我是否发现了 OpenSSL 错误,或者是否有一些我忽略的细节?下面粘贴了我的程序中的一些相关代码,以防有帮助。

// Socket setup routine, called when the server accepts a new TCP socket
int SSLSession :: SetupSSL(int sockfd)
{
  _ctx = SSL_CTX_new(SSLv23_method());
  if (_ctx)
  {
     SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);

     _ssl = SSL_new(_ctx);
     if (_ssl)
     {
        _sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
        if (_sbio)
        {
           SSL_set_bio(_ssl, _sbio, _sbio);
           SSL_set_accept_state(_ssl);

           BIO_set_nbio(_sbio, !blocking);
           ERR_print_errors_fp(stderr);

           return RESULT_SUCCESS;
        }
        else fprintf(stderr, "SSLSession:  BIO_new_socket() failed!\n");
     }
     else fprintf(stderr, "SSLSession:  SSL_new() failed!\n");
  }
  else fprintf(stderr, "SSLSession:  SSL_CTX_new() failed!\n");

  return RESULT_FAILURE;
}

// Socket read routine -- returns number of bytes read from SSL-land
int32 SSLSession :: Read(void *buffer, uint32 size)
{
  if (_ssl == NULL) return -1;

  int32 bytes = SSL_read(_ssl, buffer, size);
  if (bytes > 0) 
  {
     _sslState &= ~(SSL_STATE_READ_WANTS_READABLE_SOCKET | SSL_STATE_READ_WANTS_WRITEABLE_SOCKET);
  }
  else if (bytes == 0) return -1;  // connection was terminated
  else
  {
     int err = SSL_get_error(_ssl, bytes);
     if (err == SSL_ERROR_WANT_WRITE)
     {
        // We have to wait until our socket is writeable, and then repeat our SSL_read() call.
        _sslState &= ~SSL_STATE_READ_WANTS_READABLE_SOCKET;
        _sslState |=  SSL_STATE_READ_WANTS_WRITEABLE_SOCKET;
        bytes = 0;
     }
     else if (err == SSL_ERROR_WANT_READ)
     {
        // We have to wait until our socket is readable, and then repeat our SSL_read() call.
        _sslState |=  SSL_STATE_READ_WANTS_READABLE_SOCKET;
        _sslState &= ~SSL_STATE_READ_WANTS_WRITEABLE_SOCKET;
        bytes = 0;
     }
     else
     {
        fprintf(stderr, "SSL_read() ERROR:  ");
        ERR_print_errors_fp(stderr);
     }
  }
  return bytes;
}

// Socket write routine -- returns number of bytes written to SSL-land
int32 SSLSession :: Write(const void *buffer, uint32 size)
{
  if (_ssl == NULL) return -1;

  int32 bytes = SSL_write(_ssl, buffer, size);
  if (bytes > 0) 
  {
     _sslState &= ~(SSL_STATE_WRITE_WANTS_READABLE_SOCKET | SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET);
  }
  else if (bytes == 0) return -1;  // connection was terminated
  else
  {
     int err = SSL_get_error(_ssl, bytes);
     if (err == SSL_ERROR_WANT_READ)
     {
        // We have to wait until our socket is readable, and then repeat our SSL_write() call.
        _sslState |=  SSL_STATE_WRITE_WANTS_READABLE_SOCKET;
        _sslState &= ~SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET;
        bytes = 0;
     }
     else if (err == SSL_ERROR_WANT_WRITE)
     {
        // We have to wait until our socket is writeable, and then repeat our SSL_write() call.
        _sslState &= ~SSL_STATE_WRITE_WANTS_READABLE_SOCKET;
        _sslState |=  SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET;
        bytes = 0;
     }
     else
     {
        fprintf(stderr,"SSL_write() ERROR!");
        ERR_print_errors_fp(stderr);
     }
  }
  return bytes;
}

openssl-users 邮件列表上的某人帮助我解决了这个问题;问题是我正在使用 SSLv23_method() 设置 SSL 会话,并且在使用 SSLv23_method() 时,在 SSL 握手完成协商哪个协议(SSLv2、SSLv3、TLSv1 等)之前,不得调用 SSL_pending()是真的会用的。

由于我的应用程序不需要与旧版本的 SSL 兼容,因此我的快速解决方法是在设置过程中调用 SSLv3_method() 而不是 SSLv23_method()。如果需要向后兼容,那么我需要找出某种方法来检测协议协商何时完成,并避免在此之前调用 SSL_pending() ;但我现在将忽略这个问题,因为我不需要该功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 OpenSSL 给我一个“调用了不应调用的函数”错误? 的相关文章

  • 将集合绑定到自定义控件属性

    我没有运气尝试将数据集合绑定到我的自定义控件的属性 我已经实现了该控件的字符串属性的机制 在此处提供了一些帮助 并期望集合类型同样简单 但是我无法让它再次工作 这是我的自定义控件视图
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • EF Core 通过完全替换断开集合导航属性的更新

    使用 EF Core 5 0 我有一个 SPA 页面 可以加载Group实体及其集合Employee来自 API 的实体 var groupToUpdate await context Groups Include g gt g Emplo
  • 指向特征矩阵的指针数组

    我在代码中使用 Eigen 的 MatrixXd 矩阵 在某个时刻我需要一个 3D 矩阵 由于 Eigen 没有三维矩阵类型 因为它仅针对线性代数进行了优化 因此我创建了一个 MatrixXd 类型的指针数组 Eigen MatrixXd
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • 类的成员复制

    在学习 复制成员 概念时 书中给出了如下说法 此外 如果非静态成员是引用 const 或没有复制赋值的用户定义类型 则无法生成默认赋值 我不太明白这个声明到底想传达什么 或者说这个说法指的是哪一种场景 谢谢 该语句与编译器自动为您编写的类
  • 单例模式和 std::unique_ptr

    std unique ptr唯一地控制它指向的对象 因此不使用引用计数 单例确保利用引用计数只能创建一个对象 那么会std unique ptr与单例执行相同 单例确保只有一个实例属于一种类型 A unique ptr确保只有一个智能指针到
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • std::forward_as_tuple 将参数传递给 2 个构造函数

    我想传递多个参数以便在函数内构造两个对象 以同样的方式std pair
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • 检查 RoutedEvent 是否有任何处理程序

    我有一个自定义 Button 类 当单击它时 打开特定窗口 它总是执行相同的操作 我添加了一个可以在按钮的 XAML 中分配的 Click 事件 就像常规按钮一样 当它被单击时 我想执行 Click 事件处理程序 如果已分配 否则我想执行默
  • AES 输出是否小于输入?

    我想加密一个字符串并将其嵌入到 URL 中 因此我想确保加密的输出不大于输入 AES 是可行的方法吗 不可能创建任何始终会创建比输入更小的输出的算法 但可以将任何输出反转回输入 如果您允许 不大于输入 那么基本上您只是在谈论同构算法alwa
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 如何在c的case语句中使用省略号?

    CASE expr no commas ELLIPSIS expr no commas 我在c的语法规则中看到了这样的规则 但是当我尝试重现它时 int test float i switch i case 1 3 printf hi 它失
  • 使用restsharp序列化对象并将其传递给WebApi而不是序列化列表

    我有一个看起来像的视图模型 public class StoreItemViewModel public Guid ItemId get set public List
  • cout 和字符串连接

    我刚刚复习了我的 C 我尝试这样做 include
  • C++ Streambuf 方法可以抛出异常吗?

    我正在尝试找到一种方法来获取读取或写入流的字符数 即使存在错误并且读 写结束时间较短 该方法也是可靠的 我正在做这样的事情 return stream rdbuf gt sputn buffer buffer size 但如果streamb
  • 使我的 COM 程序集调用异步

    我刚刚 赢得 了在当前工作中维护用 C 编码的遗留库的特权 这个dll 公开使用 Uniface 构建的大型遗留系统的方法 除了调用 COM 对象之外别无选择 充当此遗留系统与另一个系统的 API 之间的链接 在某些情况下 使用 WinFo
  • 使用 QtWebEngine 将 C++ 对象暴露给 Qt 中的 Javascript

    使用 QtWebkit 可以通过以下方式将 C 对象公开给 JavascriptQWebFrame addToJavaScriptWindowObject如中所述https stackoverflow com a 20685002 5959

随机推荐

  • 从字符串编译Java源代码? [复制]

    这个问题在这里已经有答案了 有没有办法让正在运行的Java程序编译Java源代码 作为字符串传递 Class newClass Compiler compile class ABC void xyz etc etc 理想情况下 传入源代码引
  • 在 PHP 中 RESTful 上传文件

    因此 我正在编写一个脚本 该脚本将通过 RESTful 接口将视频上传到服务器 文档告诉我 我应该将数据 包括二进制视频文件 作为 POST 请求的一部分传递 我知道如何设置我的 POST 变量 但我不知道如何处理二进制数据 API 说我应
  • 在 jQuery 中替换元素并返回新元素

    如何替换 jQuery 中的元素并返回替换元素而不是被删除的元素 我有以下场景 我有很多复选框 一旦您单击其中一个 该复选框就会被加载图标取代 一旦发生一些 AJAX 事件 加载图标就会被勾号图标取代 使用 jQuery 的replaceW
  • 从弹出视图控制器传递数据

    我有两个视图控制器 我首先打开 当我按下按钮时 第二个视图控制器被推到导航控制器堆栈上 在这里 在第二个视图控制器中 我有一个表视图 当我点击某些行时 它们被选中 如复选框 并且与该行相关的一些数据被添加到数组中 现在 当我完成选择后 我想
  • 获取 gradle 构建的 aapt2 参数?

    我有兴趣尝试使用 aapt2 从命令行编译 Android 应用程序 当我尝试执行以下操作时 链接约束布局库时遇到问题aapt2 link命令 该程序从 Android studio gradle 成功构建 如何使 gradle 命令行调用
  • ASP.NET Core 2.2 中的路由本地化

    我正在使用 ASP NET Core 2 2 开发应用程序 并且正在努力解决如何实现路由本地化的问题 例如 根据请求 如果路线中未指定语言 我需要重定向到路线 en products 如果未指定语言 则从接受语言标头获取区域设置 下面的de
  • 如何在 Spring MVC 中使用延迟加载

    Spring MVC中如何使用延迟加载 我现在正在使用 eager 但这会使我的应用程序运行速度变慢 这是我的域的一部分 ManyToMany fetch FetchType EAGER JoinTable name NEWS TAG jo
  • 直接屏幕像素/帧缓冲区访问[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想尝试创建一个玩游戏的程序 IE 机器人 我希望能够直接访问屏幕上的像素 IE 让我的程序 看到 一场比赛 然后 采取行动 或者至少
  • Windows批处理文件-显示所有子文件夹

    我在使用 Windows 批处理文件返回 JUST 文件夹 忽略文件 时遇到困难 这就是我现在所拥有的 目前它正在返回文件和子子文件夹 for r g in xx do echo g 另外 假设我只想返回以几个不同前缀开头的文件夹 例如 我
  • 如何向 gitlab-ci.yml 添加多行 bash EOD 命令?

    这个问题已被问过多次 但大多数问题都很容易解决 尽管使用工具expect它没有像我预期的那样工作 usr bin expect lt
  • 在openxml中向Excel添加样式

    我想在打开的 Excel 文档中设置文本的前景色以写入文本 为此我尝试过 var stylesheet1 spreadSheet WorkbookPart WorkbookStylesPart Stylesheet Fills fills1
  • FF Addon SDK 有打开设置页面的 API 吗?

    I use 简单首选项 https developer mozilla org en US Add ons SDK High Level APIs simple prefs模块来配置插件设置 我怎么能够以编程方式打开插件的设置页面 我们这样
  • 无法使用激活器(Play Framework)加载本机库

    我正在尝试在 Play 2 4 x 应用程序中加载本机库 我编写了一个简单的测试 该测试在 IDE IntelliJ 和 SBT 中都运行良好 在这两种情况下我都设置java library path让测试运行 我在IDE中设置 Djava
  • 为什么我的 BST 根指针由于某种未知原因而发生变化?

    我正在尝试用 C 语言实现二叉搜索树数据结构 但遇到了一个错误 我的指针值由于我不明白的原因而发生变化 请参阅帖子底部的奇怪输出 删除函数和主要函数澄清输出来自何处 我的测试功能如下 int main void Bst bst Bst ca
  • 如何在 Dart 和 Flutter 中将时间四舍五入到最接近的一刻钟?

    我有一个DateTime并愿意四舍五入至 15 秒 或其他间隔 例如 2020 03 16 12 23 53 756 到 2020 03 16 12 23 45 000 和 2020 03 16 12 24 01 1234 到 2020 0
  • 如何缩进现有 OCaml 代码

    我有大约 30 000 行缩进严重的 OCaml 代码 包括 mly 和 mll 文件 并且想要缩进它们 我尝试在谷歌上搜索 ocaml indent 的变体 我能得到的最接近的结果是使用 Omlet vim 并一次缩进一行代码 在插入模式
  • 我的 React 项目中 Firestore 数据库的读取次数非常多

    我正在使用 React 和 firebase firestore 制作一个简单的 CRUD 应用程序 我目前有一组 产品 有四条记录 主页循环显示产品 import React useEffect useState from react i
  • 如何从模板类中的方法返回 NULL

    我有一个如下所示的方法 template
  • 从恶意 PDF 中提取 JavaScript

    我有一个 PDF 文件 据我所知 它包含一个 JavaScript 脚本文件 该文件会执行恶意操作 但目前还不确定具体是什么 我已经成功解压缩了 PDF 文件并获得了纯文本 JavaScript 源代码 但它的代码本身隐藏在我以前从未见过的
  • 为什么 OpenSSL 给我一个“调用了不应调用的函数”错误?

    我正在努力向我的服务器程序添加 OpenSSL 支持 通常它运行得很好 但我遇到了一个问题 首先 一些背景知识 服务器是单线程的 使用非阻塞 I O 和 select 循环来同时处理多个客户端 服务器链接到 libssl 0 9 8 dyl