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 :-)