EVP_SignInit_ex - HBSSL problem

dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

EVP_SignInit_ex - HBSSL problem

Post 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.
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: EVP_SignInit_ex - HBSSL problem

Post 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)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: EVP_SignInit_ex - HBSSL problem

Post by Antonio Linares »

Has comprobado el valor de signed ?

? signed
regards, saludos

Antonio Linares
www.fivetechsoft.com
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
User avatar
karinha
Posts: 4882
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
João Santos - São Paulo - Brasil
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
karinha
Posts: 4882
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: EVP_SignInit_ex - HBSSL problem

Post by karinha »

João Santos - São Paulo - Brasil
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: EVP_SignInit_ex - HBSSL problem

Post by Antonio Linares »

Diego,

te agradecemos mucho si compartes tu solución aquí para ayudar a otros usuarios, gracias
regards, saludos

Antonio Linares
www.fivetechsoft.com
dhf27
Posts: 14
Joined: Tue Jun 27, 2017 2:24 pm

Re: EVP_SignInit_ex - HBSSL problem

Post 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.
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: EVP_SignInit_ex - HBSSL problem

Post by Antonio Linares »

gracias Diego :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply