c - 使用 OpenSSL、SWIG 和 Perl 签署消息时出现段错误

标签 c perl openssl swig ecdsa

我们使用 SWIG 来制作可用于 Perl 的 C 加密实用程序库。我们能够生成 key 、创建摘要,但签名代码会导致段错误,我们认为这可能存在于 OpenSSL 代码本身中,但很难确定。

仅当使用 SWIG 运行代码时才会出现此问题, native C 代码可以工作。

在 Perl 中,我们称之为:

$signature = key_utils::mysignMessageWithPem($pem, $message);

它在 .i 文件中调用此代码:

%newobject mysignMessageWithPem;                                                                                                                                                                                                                                                                                              

%inline %{                                                                                                                                                                                                                                                                                                                    
  char *mysignMessageWithPem(char *pem, char *message) {                                                                                                                                                                                                                                                                      
    char *ret = malloc(145);                                                                                                                                                                                                                                                                                                  
    char *err = malloc(5);                                                                                                                                                                                                                                                                                                    
    int errorCode;                                                                                                                                                                                                                                                                                                            

    memcpy(err, "ERROR", 5);                                                                                                                                                                                                                                                                                                  

    errorCode = signMessageWithPem(pem, message, &ret);                                                                                                                                                                                                                                                                       
    char *signature = ret;                                                                                                                                                                                                                                                                                                    

    if (errorCode == NOERROR) {                                                                                                                                                                                                                                                                                               
      return signature;                                                                                                                                                                                                                                                                                                       
    } else {                                                                                                                                                                                                                                                                                                                  
      return err;                                                                                                                                                                                                                                                                                                             
    }                                                                                                                                                                                                                                                                                                                         

  }                                                                                                                                                                                                                                                                                                                           
%}                     

调用此 C 代码:

int signMessageWithPem(char *message, char *pem, char **signature) {                                                                                                                                                                                                                                                          

unsigned int meslen = strlen(message);                                                                                                                                                                                                                                                                                    
unsigned char *messagebytes = calloc(meslen, sizeof(unsigned char));                                                                                                                                                                                                                                                      
ECDSA_SIG *sig = NULL;                                                                                                                                                                                                                                                                                                    
memcpy(messagebytes, message, meslen);                                                                                                                                                                                                                                                                                    

EC_KEY *key = NULL;                                                                                                                                                                                                                                                                                                       
BIO *in = NULL;                                                                                                                                                                                                                                                                                                           
unsigned char *buffer = NULL;                                                                                                                                                                                                                                                                                             

char *sha256ofMsg = calloc(SHA256_HEX_STRING, sizeof(char));                                                                                                                                                                                                                                                              
unsigned char *outBytesOfsha256ofMsg = calloc(SHA256_STRING, sizeof(unsigned char));                                                                                                                                                                                                                                      

digestOfBytes(messagebytes, &sha256ofMsg, "sha256", meslen);                                                                                                                                                                                                                                                              
sha256ofMsg[64] = '\0';                                                                                                                                                                                                                                                                                                   
createDataWithHexString(sha256ofMsg, &outBytesOfsha256ofMsg);                                                                                                                                                                                                                                                             

in = BIO_new(BIO_s_mem());                                                                                                                                                                                                                                                                                                
BIO_puts(in, pem);                                                                                                                                                                                                                                                                                                        
PEM_read_bio_ECPrivateKey(in, &key, NULL, NULL);                                                                                                                                                                                                                                                                          

sig = ECDSA_do_sign((const unsigned char*)outBytesOfsha256ofMsg, SHA256_DIGEST_LENGTH, key);                                                                                                                                                                                                                              
int verify = ECDSA_do_verify((const unsigned char*)outBytesOfsha256ofMsg, SHA256_DIGEST_LENGTH, sig, key);                                                                                                                                                                                                                

if(verify != 1) {                                                                                                                                                                                                                                                                                                         
    return ERROR;                                                                                                                                                                                                                                                                                                         
}                                                                                                                                                                                                                                                                                                                         

int buflen = ECDSA_size(key);                                                                                                                                                                                                                                                                                             
buffer = OPENSSL_malloc(buflen);                                                                                                                                                                                                                                                                                          

int derSigLen = i2d_ECDSA_SIG(sig, &buffer);                                                                                                                                                                                                                                                                              

char *hexData = calloc(derSigLen, sizeof(char));                                                                                                                                                                                                                                                                          
memcpy(hexData, buffer-derSigLen, derSigLen);                                                                                                                                                                                                                                                                             

char *hexString = calloc(derSigLen*2+1, sizeof(char));                                                                                                                                                                                                                                                                    

hexString[derSigLen * 2] = '\0';                                                                                                                                                                                                                                                                                          
toHexString(hexData, derSigLen, hexString);                                                                                                                                                                                                                                                                               

memcpy(*signature, hexString, derSigLen*2);                                                                                                                                                                                                                                                                               
signature[derSigLen * 2] = '\0';                                                                                                                                                                                                                                                                                          

EC_KEY_free(key);                                                                                                                                                                                                                                                                                                         

BIO_free_all(in);                                                                                                                                                                                                                                                                                                         
free(sha256ofMsg);                                                                                                                                                                                                                                                                                                        
free(outBytesOfsha256ofMsg);                                                                                                                                                                                                                                                                                              
free(hexData);                                                                                                                                                                                                                                                                                                            
free(hexString);                                                                                                                                                                                                                                                                                                          

return NOERROR;
}                  

并返回段错误。我们得到的信息最多的错误是 perl 在 EC_KEY_get_key_method_data() 中因 SIGSEGV 崩溃

完整代码在这里:https://github.com/aleitner/bitpay-perl/tree/stack-overflow-question

这是 SSL 的错误,还是我们做错了?

最佳答案

这个问题的答案是:我们以错误的顺序调用参数。

说真的。该行:

$signature = key_utils::mysignMessageWithPem($pem, $message);

需要:

$signature = key_utils::mysignMessageWithPem($message, $pem);

我们实际上做错了什么。我很想删除这个问题,但也许答案可以作为一个警示或其他什么。

关于c - 使用 OpenSSL、SWIG 和 Perl 签署消息时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30170929/

相关文章:

c - Linux 内核模块 - 创建目录

c++ - 管道以提供文件作为 C 程序的输入

android - 如何检查Android应用程序的OpenSSL库版本

perl - 按 Perl 哈希的哈希值哈希排序

Perl TCP、打印、选择和 sysread - 缓冲行为

openssl - 将 CSR 专有名称字段作为参数传递给 OpenSSL

c - OpenSSL 1.0.2 和错误 "SSL_CTX_new:library has no ciphers"

c++ - vector 、矩阵和四元数的缓存性能

c - 使用 union/结构在纯 C 中创建广义列表对象

perl - awk 或 Perl 删除数据不完整行的解决方案