C EVP_更新永不返回

C EVP_更新永不返回,c,lua,openssl,C,Lua,Openssl,我正在重写LuaCrypto,使其在Lua5.3上运行并支持SSL 1.1.0。(它的原始代码在Lua5.1上运行,支持SSL,最高可达1.0)。 LuaCrypto和Lua5.3之间不兼容的主要原因是加载机制,该机制经历了重大修改,我通过替换与加载库相关的所有函数使其正常工作。 LuaCrypto和SSL 1.1.0之间不兼容的主要原因是,现在SSL结构(特别是EVP和HMAC)是不透明的,编译器不再知道这些结构的内部或大小。 不幸的是,LibCrypto依赖于知道这些结构的大小,将它们作为用

我正在重写LuaCrypto,使其在Lua5.3上运行并支持SSL 1.1.0。(它的原始代码在Lua5.1上运行,支持SSL,最高可达1.0)。

LuaCrypto和Lua5.3之间不兼容的主要原因是加载机制,该机制经历了重大修改,我通过替换与加载库相关的所有函数使其正常工作。

LuaCrypto和SSL 1.1.0之间不兼容的主要原因是,现在SSL结构(特别是EVP和HMAC)是不透明的,编译器不再知道这些结构的内部或大小。

不幸的是,LibCrypto依赖于知道这些结构的大小,将它们作为用户数据加载到Lua状态。然后,显而易见的解决方案是重写库,使其将EVP和HMAC结构加载为lightuserdata,并重写垃圾收集器元方法以调用SSL free/destroy/Anwhere,以便在不再需要这些结构时从这些结构中删除内存。

我做到了这一点,只要我在一步中运行加密/解密/摘要,这一切都很有趣。每当我尝试通过EVP_UPDATE()函数递增地使用EVP时,调用此函数时机器就会冻结,但如果我尝试在一个步骤中运行解密,则不会冻结。

以下是违规代码:

static HANDLER_EVP *evp_pget(lua_State *L, int i)
{
  if (luaL_checkudata(L, i, LUACRYPTO_EVPNAME) == NULL)
    luaL_typerror(L, i, LUACRYPTO_EVPNAME);
  return lua_touserdata(L, i);
}

void evp_pnew(lua_State *L, HANDLER_EVP *c)
{
  lua_pushlightuserdata(L, c);
  luaL_getmetatable(L, LUACRYPTO_EVPNAME);
  lua_setmetatable(L, -2);
}

static int evp_fnew(lua_State *L)

    {
  HANDLER_EVP *c = NULL;
  const char *s = luaL_checkstring(L, 1);
  DIGEST_TYPE type = DIGEST_BY_NAME(s);

  if (IS_DIGEST_INVALID(type)) {
    luaL_argerror(L, 1, "invalid digest type");
    return 0;
  }

    static int evp_update(lua_State *L)
{
  HANDLER_EVP *c = evp_pget(L, 1);
  size_t s_len;
  const char *s = luaL_checklstring(L, 2, &s_len);
  dumpStack(L);
  debug(L, "c=%p, s=\"%s\", s_len=%d", c, s, s_len);
  EVP_UPDATE(c, s, s_len); // HERE IS THE PROBLEM
  debug(L, "I AM HERE"); // never run

  lua_settop(L, 1);
  return 1;
}
这是Lua测试:

 for i, t in ipairs({"sha1", "md5", "sha1", "hmac"}) do
  print("testing " .. t)
  local d
  if (t == "hmac") then
    d = hmac.new("sha1", "luacrypto")
  else
    d = evp.new(t)
  end

  assert(io.input(F))
  print("all", d:digest(io.read("*all")), F, t)

  d:reset()

  assert(io.input(F))

  while true do
   local c = io.read(1)
   if c == nil then break end
   d:update(c)
  end
  print("loop", d:digest(), F, t)
  if (t ~= "hmac") then
    print("again", d:digest(), F, t)
    assert(io.input(F))
    print("alone", hmac.digest("sha1", io.read("*all"), "luacrypto"), F, t);
  else
    assert(io.input(F))
    print("alone", hmac.digest("sha1", io.read("*all"), "luacrypto"), F, t);
  end

  assert(io.input(F))
  d:reset()

  while true do
   local c = io.read(math.random(1, 16))
   if c == nil then break end
   d:update(c)
  end

  report("reset", d:digest(d), F, t)
  report("known", _G[t .. "_KNOWN"], F, t)
  print("")

end
这是输出:

testing sha1

TAG:lua_print LINE:141  

c=0xc14a8

TAG:lua_print LINE:141  

all     d6ed6e26ebeb37ba0792ec75a3d0b4dcec279d25           /mtd0/message      sha1

TAG:lua_print LINE:141  

estou aqui

TAG:lua_print LINE:141  

1: userdata

2: "T"



TAG:lua_print LINE:141  

c=0xc14a8, s="T", s_len=1

我缺少什么?

不能为light userdata设置元表


您需要将每个SSL结构指针放入一个(重)用户数据中。

好的,伙计们,我得到了这个。问题似乎不在原来的位置。

显然,reset()函数因某种原因而存在缺陷。

这是我为重置所做的:

static int evp_reset(lua_State *L)
{
#ifdef CRYPTO_OPENSSL
  EVP_MD_CTX_reset(c);
#elif CRYPTO_GCRYPT
  gcry_md_reset(*c);
#endif

  return 0;
}
出于某种原因,
EVP\u MD\u CTX\u reset()
没有按照文档中的说明执行操作,也没有清理结构。因此,我尝试通过以下方式手动执行此操作:

static int evp_reset(lua_State *L)
{
  HANDLER_EVP *c = evp_pget(L, 1);
#ifdef CRYPTO_OPENSSL
  const EVP_MD *t = EVP_MD_CTX_md(c);
  //EVP_MD_CTX_reset(c);
  EVP_MD_CTX_init(c);
  EVP_DigestInit_ex(c, t, NULL);
#elif CRYPTO_GCRYPT
  gcry_md_reset(*c);
#endif

  return 0;
}

这消除了故障。这似乎是SSL库中的一个bug

我为light userdata设置元表没有问题。也许这是旧版本lua的一个限制。您已经为所有light userdata值设置了相同的meltable。只有表和重userdata值可以有单独的元表。这没有意义。。。轻用户数据比任何其他lua类型更需要_gc元方法,因为它需要在C端显式地进行dellocation,而重用户数据在丢失lua状态的所有引用时会自动进行dellocation。如果这是Lua开发人员的一个深思熟虑的决定,那么这是一个非常糟糕的决定。。。但不管怎样,正如你所指出的,总有办法解决的。