You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
2.3 KiB
C

#include "keys.h"
#include "model/crypto/base64.h"
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/err.h>
struct crypto_keys
{
EVP_PKEY* pubkey;
EVP_PKEY* privkey;
};
struct crypto_keys* crypto_keys_new()
{
struct crypto_keys* k;
k = malloc(sizeof(*k));
memset(k,0,sizeof(*k));
return k;
}
void crypto_keys_free( struct crypto_keys* keys )
{
if( !keys ) { return; }
if( keys->pubkey ) {
EVP_PKEY_free(keys->pubkey);
}
if( keys->privkey ) {
EVP_PKEY_free(keys->privkey);
}
free(keys);
}
bool crypto_keys_load_private( struct crypto_keys* keys, const char* filename )
{
if( keys->privkey ) {
EVP_PKEY_free( keys->privkey );
keys->privkey = NULL;
}
FILE* f = fopen(filename,"r");
keys->privkey = PEM_read_PrivateKey( f, NULL, NULL, NULL );
fclose(f);
return !!keys->privkey;
}
bool crypto_keys_load_public( struct crypto_keys* keys, const char* filename )
{
if( keys->pubkey ) {
EVP_PKEY_free( keys->pubkey );
keys->pubkey = NULL;
}
FILE* f = fopen(filename,"r");
keys->pubkey = PEM_read_PUBKEY( f, NULL, NULL, NULL );
fclose(f);
return !!keys->pubkey;
}
char* crypto_keys_sign( struct crypto_keys* keys, void* data, unsigned int size )
{
char buffer[512];
char* result = NULL;
char* sign_binary = NULL;
EVP_PKEY_CTX* ctx = NULL;
if( !keys->privkey ) { return NULL; }
// Setup for signature
// Code based on https://www.openssl.org/docs/man3.1/man3/EVP_PKEY_sign.html
ctx = EVP_PKEY_CTX_new(keys->privkey, NULL /* no engine */);
if( !ctx ) { goto failed; }
if( EVP_PKEY_sign_init(ctx) <= 0 ) { goto failed; }
if( EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ) { goto failed; }
if( EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0 ) { goto failed; }
size_t siglen;
if( EVP_PKEY_sign(ctx, NULL, &siglen, data, size ) <= 0 ) { goto failed; }
sign_binary = malloc(siglen);
if( !sign_binary ) { goto failed; }
int retcode = EVP_PKEY_sign(ctx, sign_binary, &siglen, data, size);
if( retcode <= 0 ) {
ERR_error_string_n( retcode, buffer, sizeof(buffer) );
printf( "Failed to create signature: %s\n", buffer );
goto failed;
}
result = base64_strict_encode( sign_binary, siglen );
cleanup:
free(sign_binary);
EVP_PKEY_CTX_free(ctx);
return result;
failed:
free(result); result = NULL;
goto cleanup;
}