Page 1 of 2
EVP_SignInit_ex - HBSSL problem
Posted: Mon Dec 18, 2017 9:10 pm
by dhf27
Hi, I'm trying to use "EVP_SignInit_ex" but when I run the program it returns the sig variable empty. The "PEM_READ_BIO_RSAPRIVATEKEY" works fine, but the signing routine does not.
Hola, Estoy tratando de usar "EVP_SignInit_ex" pero cuando ejecuto el programa me retirna vacia la variable "sig". El
"PEM_READ_BIO_RSAPRIVATEKEY" funciona bien, pero la rutina de firmado no.
Code: Select all
#include "hbssl.ch"
Function main( )
Local cTx, signed, txt, sig , cString, privatekeym, bioe
setmode(25,80)
clear
#pragma __cstream|cString:=%s
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,7EDF8C06409FC8D1
w2i5vWLCOvrExPC4+FMwGQBwxXdGE7FY5Jgr6UstEN+b6l7UVSdRXEkT/Ng6RDZF
jViFPKBSrTAzEnvyNesqPBZMwRPKSEZSj+XcS/dHoz7hrbFTNBzKmDL8CJ67k2Lw
4UwtTtmTkU6L++NTfP6ImvxfaQYCkFK9D42qB7pzAAA27aGZMJCotECqVrekeCed
Tx7EMa7Vf2ToGTsvHBphy7Nwe/8Kijdb0wQIj0ZQWGa2vkYjICauAz9vfOv1xaXe
+H90c6xhVqRCv0uum3pGkqsrdJm0mBnr1gstFEDI+S1Lwr80WWBSQjCBsytfxc8j
dNXG8qXm59/n01vfHaZTtStd6mVa+eJwNRMHP0pisoxCTBPTtF/LOaZvOlbYB+r4
Hbxs5Bp0+YZp9RIipA3uagvtcTk7oHzx6v72amd3egli/DL1OY/ZjvVzHe9/dh6K
LZE2mpAHXtnHe8Rlg4CSPMvyFgN2OZXfbc64FjZcglldIoLwhr7kuLzb0zWv8sOz
jOO+uKNzyjDl5R2ay9YCANUpWVGOrpRrU6C/TzbltcxyEVKk8riKAKCsYf+De3Ee
SwPgouYGV8RgfzAwhwesibA1By1cLS/alCESH+9P2R39VHPB7MzjLc8FyNe3xAQJ
VGue9TIkMgy7RW1VFWLcLsCArTEAl83bv+BQ+YaPp9aLNq8bL5vfU2od0R7LXIOe
jH09fWcojNNLfmZU0Jzy7viUiScTtNqpqoH0qPI1hkisvELqXKhW1Lpkr56Ij8IL
B0NDIZKbaPJHHPb9Ne7nQECzv0/kzmAley9UMTZ1M7fq6KYemR0LsA==
-----END RSA PRIVATE KEY-----
#pragma __endtext
SSL_INIT()
ERR_load_PEM_strings()
OpenSSL_add_all_algorithms()
OpenSSL_add_all_ciphers()
PrivateKey := EVP_PKEY_NEW()
bioe := BIO_new_fd( 1, HB_BIO_NOCLOSE )
keyPtr := PEM_READ_BIO_RSAPRIVATEKEY( bio := BIO_new_mem_buf( cString ), "test" )
? ; ERR_print_errors( bioe ) //show if any error
EVP_PKEY_ASSIGN_RSA(PrivateKey,keyptr)
ctx := EVP_MD_CTX_create()
EVP_MD_CTX_init( ctx )
txt := "text to sign"
signed := ""
EVP_SignInit_ex(ctx, HB_EVP_MD_SHA1)
EVP_SignUpdate(ctx, txt )
EVP_SignFinal(ctx, @signed, PrivateKey)
sig := HB_BASE64ENCODE(signed)
? sig
return
Thanks/Gracias
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 4:36 am
by Antonio Linares
Diego,
Entiendo que estás siguiendo el ejemplo publicado por Rafa Carmona:
http://forums.fivetechsupport.com/viewt ... 87#p126487
En el post de Rafa, él menciona a Martin Gamez como autor de ese código.
Intentemos contactar con Martin Gamez para que nos ayude
Rafa, puedes echarnos una mano ? gracias
(le he enviado un email a Rafa para localizar a Martín Gamez)
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 4:43 am
by Antonio Linares
Has comprobado el valor de signed ?
? signed
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 10:09 am
by dhf27
Antonio, ambas variables sig y signed vuelven vacias.
Tal cual comentaba el problema esta en la parte de firmado. Tambien probe abrir la clave privada de esta manera directamente desde un archivo...
keyPtr := PEM_READ_BIO_RSAPRIVATEKEY( "cert.pem" , "test" ) // lee el archivo
Y hace lo mismo. Y estoy seguro que la decodifica bien ya que si le cambio la clave "test" por otra tira "Bad decrypt" de error.
Gracias
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 12:49 pm
by dhf27
Agrego un dato....
Grabe los resultados de las funciones...
ret=EVP_SignInit_ex(ctx, HB_EVP_MD_SHA1)
? ret
ret=EVP_SignUpdate(ctx, txt )
? ret
ret=EVP_SignFinal(ctx, @signed, PrivateKey)
? ret
Y me devuelve...
1
1
0
O sea que el problema esta en EVP_SignFinal ya que el retorno deberia ser 1 cuando se hizo correctamente.
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 12:57 pm
by karinha
Miar se ayuda:
Code: Select all
/*
* Copyright 2009 Viktor Szakats (vszakats.net/harbour)
*/
#include "FiveWin.ch"
#include "hbssl.ch"
// #require "hbssl"
PROCEDURE Main()
LOCAL cString
LOCAL bio
LOCAL bioe
SSL_init()
? ERR_load_PEM_strings()
? OpenSSL_add_all_algorithms()
bioe := BIO_new_fd( 1, HB_BIO_NOCLOSE )
? PEM_READ_BIO_RSAPRIVATEKEY( "privkey.pem", {| lWrite | Output( "Callback (block)", lWrite, hb_eol() ), "test" } )
? ; ERR_print_errors( bioe )
? PEM_READ_BIO_RSAPRIVATEKEY( "privkey.pem", @cb_function() )
? ; ERR_print_errors( bioe )
? PEM_READ_BIO_RSAPRIVATEKEY( "privkey.pem", "test" )
? ; ERR_print_errors( bioe )
? PEM_READ_BIO_RSAPUBLICKEY( "privkey.pem", {| lWrite | Output( "Callback (block)", lWrite, hb_eol() ), "test" } )
? ; ERR_print_errors( bioe )
? PEM_READ_BIO_RSAPUBLICKEY( "privkey.pem", "test" )
? ; ERR_print_errors( bioe )
#pragma __cstream|cString:=%s
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,7EDF8C06409FC8D1
w2i5vWLCOvrExPC4+FMwGQBwxXdGE7FY5Jgr6UstEN+b6l7UVSdRXEkT/Ng6RDZF
jViFPKBSrTAzEnvyNesqPBZMwRPKSEZSj+XcS/dHoz7hrbFTNBzKmDL8CJ67k2Lw
4UwtTtmTkU6L++NTfP6ImvxfaQYCkFK9D42qB7pzAAA27aGZMJCotECqVrekeCed
Tx7EMa7Vf2ToGTsvHBphy7Nwe/8Kijdb0wQIj0ZQWGa2vkYjICauAz9vfOv1xaXe
+H90c6xhVqRCv0uum3pGkqsrdJm0mBnr1gstFEDI+S1Lwr80WWBSQjCBsytfxc8j
dNXG8qXm59/n01vfHaZTtStd6mVa+eJwNRMHP0pisoxCTBPTtF/LOaZvOlbYB+r4
Hbxs5Bp0+YZp9RIipA3uagvtcTk7oHzx6v72amd3egli/DL1OY/ZjvVzHe9/dh6K
LZE2mpAHXtnHe8Rlg4CSPMvyFgN2OZXfbc64FjZcglldIoLwhr7kuLzb0zWv8sOz
jOO+uKNzyjDl5R2ay9YCANUpWVGOrpRrU6C/TzbltcxyEVKk8riKAKCsYf+De3Ee
SwPgouYGV8RgfzAwhwesibA1By1cLS/alCESH+9P2R39VHPB7MzjLc8FyNe3xAQJ
VGue9TIkMgy7RW1VFWLcLsCArTEAl83bv+BQ+YaPp9aLNq8bL5vfU2od0R7LXIOe
jH09fWcojNNLfmZU0Jzy7viUiScTtNqpqoH0qPI1hkisvELqXKhW1Lpkr56Ij8IL
B0NDIZKbaPJHHPb9Ne7nQECzv0/kzmAley9UMTZ1M7fq6KYemR0LsA==
-----END RSA PRIVATE KEY-----
#pragma __endtext
? PEM_READ_BIO_RSAPRIVATEKEY( bio := BIO_new_mem_buf( cString ), {| lWrite | QOut( "Callback", lWrite, hb_eol() ), "test" } )
? ; ERR_print_errors( bioe )
BIO_free( bio )
? PEM_READ_BIO_RSAPRIVATEKEY( bio := BIO_new_mem_buf( cString ), "test" )
? ; ERR_print_errors( bioe )
BIO_free( bio )
? PEM_READ_BIO_RSAPRIVATEKEY( bio := BIO_new_mem_buf( cString ), "<wrong>" )
? ; ERR_print_errors( bioe )
BIO_free( bio )
BIO_free( bioe )
RETURN
STATIC FUNCTION cb_function( lWrite )
? "Callback (func)", lWrite
RETURN "test"
STATIC FUNCTION Output( ... )
// ? ...
RETURN NIL
https://github.com/vmware/harbor/blob/m ... te_key.pem
http://www.pctoledo.com.br/forum/viewto ... f=4&t=9250
Regards, saludos.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 2:22 pm
by dhf27
Necesito ayuda para la funcion EVP_SignInit_ex. En los ejemplos de \contrib\hbssl\tests no figura esta funcion....
Gracias
Diego.
---------------------------
I need help for EVP_SignInit_ex function. In \contrib\hbssl\tests this function does not exist.
Thanks
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 2:28 pm
by Antonio Linares
Diego,
> O sea que el problema esta en EVP_SignFinal ya que el retorno deberia ser 1 cuando se hizo correctamente
https://wiki.openssl.org/index.php/Manu ... t_error(3)
RETURN VALUES
EVP_SignInit_ex(), EVP_SignUpdate() and EVP_SignFinal() return 1 for success and 0 for failure.
EVP_PKEY_size() returns the maximum size of a signature in bytes.
The error codes can be obtained by ERR_get_error(3).
Llama a:
? ERR_GET_ERROR()
después de mostrar el cero
y a:
See ERR_GET_LIB(3) for obtaining information about location and reason of the error, and ERR_error_string(3) for human-readable error messages.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 2:30 pm
by karinha
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 2:45 pm
by dhf27
Antonio Linares wrote:Diego,
> O sea que el problema esta en EVP_SignFinal ya que el retorno deberia ser 1 cuando se hizo correctamente
https://wiki.openssl.org/index.php/Manu ... t_error(3)
RETURN VALUES
EVP_SignInit_ex(), EVP_SignUpdate() and EVP_SignFinal() return 1 for success and 0 for failure.
EVP_PKEY_size() returns the maximum size of a signature in bytes.
The error codes can be obtained by ERR_get_error(3).
Llama a:
? ERR_GET_ERROR()
después de mostrar el cero
y a:
See ERR_GET_LIB(3) for obtaining information about location and reason of the error, and ERR_error_string(3) for human-readable error messages.
ERR_GET:_ERROR() devuelve 0
ERR_GET_LIB(3) devuelve "error:00000003:lib(0):func(0):BN lib"
peeero este error lo devuelve en cualquier parte del programa. O sea que si pongo que lo muestre en cualquier linea luego de SSL_INIT() muestra ese mismo mensaje.
Diego
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 19, 2017 2:56 pm
by dhf27
I had already seen it, but I do not understand what It's trying to do the HB function.
---
Ya lo habia mirado, pero lo que no entiendo que esta tratando de hacer la funcion de HB.
Code: Select all
HB_FUNC( EVP_SIGNFINAL )
{
if( hb_EVP_MD_CTX_is( 1 ) && hb_EVP_PKEY_is( 3 ) )
{
EVP_MD_CTX * ctx = hb_EVP_MD_CTX_par( 1 );
if( ctx )
{
unsigned char * buffer = ( unsigned char * ) hb_xgrab( EVP_PKEY_size( hb_EVP_PKEY_par( 3 ) ) + 1 );
unsigned int size = 0;
hb_retni( EVP_SignFinal( ctx, buffer, &size, hb_EVP_PKEY_par( 3 ) ) );
if( size > 0 )
{
if( ! hb_storclen_buffer( ( char * ) buffer, ( HB_SIZE ) size, 2 ) )
hb_xfree( buffer );
}
else
{
hb_xfree( buffer );
hb_storc( NULL, 2 );
}
}
}
else
hb_errRT_BASE( EG_ARG, 2010, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Sat Dec 23, 2017 8:32 pm
by dhf27
Hola, despues de romperme la cabeza encontre la manera de firmar un archivo cualquiera teniendo un .crt(certificado) y su correspondiente .key.
En argentina como en otros paises se pide esto para obtener un ticket de acceso para acceder a los diferentes webservices para factura electronica.
Lo necesario para hacer esto no esta en HBSSL. Por lo cual iba a estar toda la vida tratando de hacerlo.
Para el que lo necesite o le interese le comparto lo necesario para agregar a HBSSL y poder hacerlo directamente desde Harbour sin necesidad de utilizar Openssl por linea de comando.
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Tue Dec 26, 2017 10:39 am
by Antonio Linares
Diego,
te agradecemos mucho si compartes tu solución aquí para ayudar a otros usuarios, gracias
Re: EVP_SignInit_ex - HBSSL problem
Posted: Wed Dec 27, 2017 10:14 am
by dhf27
Hola, esta es la funcion que habria que agregar en C para luego poder utilizarla desde Harbour. Yo particularmente inserte el codigo al final del archivo contrib\hbssl\evpmd.c y luego compile el nuevo HBSSL.
La versiones de Openssl que utilice fueron estas....
https://slproweb.com/download/Win32OpenSSL-1_0_2n.exe
https://slproweb.com/download/Win64OpenSSL-1_0_2n.exe
Nuevo codigo en C para insertar...
Code: Select all
HB_FUNC( HB_SIGNFILE )
{
// HB_SIGNFILE( Archivo a firmar, Archivo .CRT, Archivo .Key, Archivo a Firmar)
BIO *in = NULL, *tbio = NULL, *out = NULL;
CMS_ContentInfo *cms = NULL;
RSA *rsa;
X509* x509;
EVP_PKEY* priKey;
const char *fileToSign = hb_parcx(1);
const char *certFile = hb_parcx(2);
const char *keyFile = hb_parcx(3);
const char *toSignFile = hb_parcx(4);
int flags = CMS_DETACHED;
FILE *archivo;
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
flags &= ~CMS_DETACHED; //-nodetach
flags |= CMS_PARTIAL;
archivo = fopen(keyFile, "r");
if (!archivo) {
hb_retni(2); // problema al leer archivo keyFile
return;
}
rsa = PEM_read_RSAPrivateKey(archivo,&rsa, NULL, "");
fclose(archivo);
if(rsa == NULL) {
hb_retni(3); //error al crear objeto RSA
return;
}
if(!RSA_check_key(rsa)) {
hb_retni(4); //el keyFile es invalido
return;
}
archivo = fopen(certFile, "r");
if (archivo == NULL) {
hb_retni(5); // problema al leer archivo certFile
return;
}
x509 = PEM_read_X509(archivo, NULL, NULL, NULL);
fclose(archivo);
if (x509 == NULL) {
hb_retni(6); //error al crear objeto X509
return;
}
priKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(priKey, rsa);
if (X509_check_private_key(x509, priKey) == 0) {
hb_retni(7); //el Key no se corresponde al Crt
return;
}
if (!(archivo = fopen(fileToSign, "r"))) {
hb_retni(8); //error al abrir fileToSign
return;
}
in = BIO_new_file(fileToSign, "r");
if (!in) {
hb_retni(9); //error al crear objeto in
return;
}
cms = CMS_sign(x509, priKey, NULL, in, flags);
if (cms == NULL) {
hb_retni(10); //error al crear objeto cms
return;
}
CMS_final(cms, in, NULL, flags);
if (!cms) {
hb_retni(11); //error al cerrar el objeto cms
return;
}
out = BIO_new_file(toSignFile, "wb");
if (!out) {
hb_retni(12); //error al abrir el archivo toSignFile
return;
}
//if(!PEM_write_bio_CMS_stream(out,cms, in, flags)) lo graba en formato PEM
//if (!SMIME_write_CMS(out, cms, in, flags)) lo graba en formato SMIME
if (!i2d_CMS_bio_stream(out,cms, in, flags)) {//lo graba en formato DER
hb_retni(13); //error al grabar el archivo toSignFile
return;
}
CMS_ContentInfo_free(cms);
X509_free(x509);
EVP_PKEY_free(priKey);
BIO_free(in);
BIO_free_all(out);
BIO_free(tbio);
hb_retni( 1 );
return;
}
Ademas al comienzo del mismo archivo donde se declaran los "include", inclui tambien estos...
Code: Select all
#include <openssl/cms.h>
#include <stdio.h>
#include <hbapi.h>
#include <fcntl.h>
Y este es el ejemplo para utilizarlo desde Harbour.
Code: Select all
/*
hbmk2 tip4.prg hbssl.hbc
*/
#require "hbssl"
#include "hbssl.ch"
Function main( )
Local ERROR
setmode(25,80)
clear
/*Posibles resultados de ERROR:
1: Sin Errores
2: problema al leer archivo keyFile
3: error al crear objeto RSA
4: el keyFile es invalido
5: problema al leer archivo certFile
6: error al crear objeto X509
7: el Key no se corresponde al Crt
8: error al abrir fromSignFile
9: error al crear objeto in
10: error al crear objeto cms
11: error al cerrar el objeto cms
12: error al crear objeto out
13: error al grabar el archivo toSignFile*/
SSL_INIT()
ERROR:=HB_SIGNFILE2( "TRA.XML", "CERT.CRT", "CERT.KEY", "TRA.TMP")
if (ERROR!=1)
? ERROR
endif
return
Basicamente lo que haria esta funcion es firmar un archivo en formato DER a partir de un Certificado(.CRT) y una clave privada(.KEY).
Desde OpenSSL esto lo venia haciendo por linea de comando de esta manera...:
C:\OPENSSL\BIN> openssl smime -sign -in c:\tra.xml -out c:\tra.tmp -signer c:\cert.crt -inkey c:\cert.key -outform DER -nodetach
Por favor tener en cuenta que no tengo mucho conocimiento en la manera que se envian los datos entre C y Harbour. Pero con prueba y error mas o menos lo fui sacando. Obviamente esto se puede optimizar, pero para arrancar sirve como ejemplo. Ya lo implemente y funciona perfecto. No se olviden que como casi todo lo que utiliza HBSSL hay que incluir los dll que vienen con OpenSSL en la misma carpeta que el ejecutable para que todo funcione.
Para llegar a esta solucion depure el codigo fuente de Openssl linea a linea y asi fui viendo las funciones que se ejecutaban cuando se utilizaba la linea de comando y asi armando la funcion en C.
Diego.
Re: EVP_SignInit_ex - HBSSL problem
Posted: Wed Dec 27, 2017 12:37 pm
by Antonio Linares
gracias Diego