2

我们使用 SWIG 为 Perl 提供了一个 C 加密实用程序库。我们能够生成密钥、创建摘要,但签名代码会导致分段错误,我们认为这可能在 OpenSSL 代码本身中,但很难确定。

此问题仅在使用 SWIG 运行代码时出现,本机 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;
}                  

并返回Segmentation Fault。我们得到的信息最多的错误是perl crashed with SIGSEGV in EC_KEY_get_key_method_data()

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

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

4

1 回答 1

2

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

严重地。该行:

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

需要是:

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

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

于 2015-05-11T17:33:32.443 回答