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.