openssl EC_KEY_new_by_curve_name crashed with no information - c

In my get_keypair function,I want to create an EC_KEY structure by EC_KEY_new_by_curve_name(NID_secp256k1) .By doing so,I got a crash on my vs2019 with no details.Below comes my code.
bool get_keypair(EC_KEY** key, bool getcompressed,uint8_t* rawprikey, uint8_t rawprikeylen) {
BIGNUM* priv; //prikey bignum
BN_CTX* ctx; //hold the operation
const EC_GROUP* group;
EC_POINT* pub; //pubkey point st
*key = EC_KEY_new_by_curve_name(NID_secp256k1); //secp256k1, !!!crashed here
if (*key == 0) {
printf("new ec key failed");
exit(-1);
}
priv = BN_new(); //create bignum
BN_bin2bn(rawprikey, 32, priv); //fill the bigbum with prikey
EC_KEY_set_private_key(*key, priv); //put prikey bignum to key pair
ctx = BN_CTX_new(); //create context
BN_CTX_start(ctx); //init context
group = EC_KEY_get0_group(*key); //G
pub = EC_POINT_new(group); //create pub st
EC_POINT_mul(group, pub, priv, NULL, NULL, ctx); //P = n * G
EC_KEY_set_public_key(*key, pub); //fill the key pair, !!!crashed here
EC_KEY_set_conv_form(*key, getcompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); //compressd or not
uint64_t pubkeylen = i2o_ECPublicKey(*key, NULL);
uint8_t *pubkey = calloc(pubkeylen, sizeof(uint8_t));
uint8_t* pub_copy = pubkey;
if (i2o_ECPublicKey(*key, &pub_copy) != pubkeylen) {
puts("Unable to decode public key");
return false;
}
/*for (int i = 0; i < *pubkeylen; i++) {
printf("%02X", (*pubkey)[i]);
}*/
EC_POINT_free(pub);//free all
BN_CTX_end(ctx);
BN_CTX_free(ctx);
BN_clear_free(priv);
return true;
}
Just a proof of work,No checks was added.
And I keet rerun the program many times,saw that the program will crash at different code.
Below are some pictures captured when the program crashed.
crashed at EC_KEY_new_by_curve_name
crashed at EC_KEY_set_public_key
crashed on main exit
linked librares

You need to allocate "EC_KEY** key" variable before call get_keypair() function.

Related

Output data to abuffersrc and pull from abuffersink with multiple inputs using FFMPEG afir filter

I want to understand why av_buffersink_get_frame() always return AVERROR(EAGAIN).
I use this algorithm:
Open input file input.mp3, create decoder for input file
Open signal file signal.wav, create decoder for signal file
Create filter graph and inputs/outputs with function avfilter_graph_parse2("[in0][in1]afir[out], &inputs, &outputs")
Create abuffersrc for every inputs with names "in0", "in1"
Create one abuffersink for one outputs with name "out"
Read and decode samples with methods av_read_frame(), avcodec_send_packet(), avcodec_receive_frame(), put samples to abuffersrc with av_buffersrc_add_frame() and trying to read samples from abuffersink with av_buffersink_get_frame() - HERE I get AVERROR(EAGAIN) for every call
Please, help!
I've tried to read all samples and push its to abuffersrc for input and signal pipes in first step and and call av_buffersink_get_frame one time in second step. I got AVERROR(EGAIN) again.
I've tried to config two outputs with names "in0" and "in1" and one input with name "out" and call avfilter_graph_parse_ptr() as done in here:
static AVFilterContext *init_buffersrc(AVCodecContext *decoder, AVFilterGraph *filter_graph, const char *pad_name) {
AVFilterContext *buffersrc = NULL;
uint8_t args[1024];
snprintf(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64"",
decoder->time_base.num, decoder->time_base.den, decoder->sample_rate, av_get_sample_fmt_name(decoder->sample_fmt), decoder->channel_layout);
CHECK_AV(avfilter_graph_create_filter(&buffersrc, avfilter_get_by_name("abuffer"), pad_name, args, NULL, filter_graph));
return buffersrc;
}
static AVFilterContext *init_buffersink(AVFilterGraph *filter_graph) {
AVFilterContext *buffersink = NULL;
CHECK_AV(avfilter_graph_create_filter(&buffersink, avfilter_get_by_name("abuffersink"), "out", NULL, NULL, filter_graph));
return buffersink;
}
static void init_complex_graph(const char *desc, Context *ctx) {
AVFilterGraph *filter_graph;
AVFilterInOut *inputs = avfilter_inout_alloc();
AVFilterInOut **outputs = (AVFilterInOut**) av_malloc(ctx->nb_input_files*sizeof(AVFilterInOut *));
char *dump;
uint8_t pad_name[64];
filter_graph = ctx->filter_graph = avfilter_graph_alloc();
filter_graph->nb_threads = 1;
for (int i = 0; i< ctx->nb_input_files; ++i) {
outputs[i] = avfilter_inout_alloc();
}
for (int i = 0; i < ctx->nb_input_files; ++i) {
AVFilterContext *buffersrc;
snprintf(pad_name, sizeof(pad_name), "in%d", i);
buffersrc = init_buffersrc(ctx->input_files[i]->decoder, filter_graph, pad_name);
ctx->input_files[i]->buffersrc = buffersrc;
outputs[i]->name = av_strdup(pad_name);
outputs[i]->filter_ctx = buffersrc;
outputs[i]->pad_idx = 0;
if (i == ctx->nb_input_files - 1) {
outputs[i]->next = NULL;
}
else {
outputs[i]->next = outputs[i + 1];
}
}
ctx->output_file->buffersink = init_buffersink(filter_graph);
inputs->name = av_strdup("out");
inputs->filter_ctx = ctx->output_file->buffersink;
inputs->pad_idx =0;
inputs->next = NULL;
CHECK_AV(avfilter_graph_parse_ptr(filter_graph, desc, &inputs, outputs, NULL));
CHECK_AV(avfilter_graph_config(filter_graph, NULL));
}
// Call init_complex_graph("[in0][in1]afir[out]", SOME_CONTEXT);
and still nothing.

Copy TCHAR* string from other thread

I want to copy data from another thread to struct and print. _tpintf() doesnt show russian letters corret.
in concole I see this, but I expect to see "IN THREAD текст клиент1". Please explain why tchar doesnt work? Also I noticed that if I use _tcprintf, "клиент1" shows correct, but "текст" become wrong
Code of thread function which tries to copy data from another
static DWORD WINAPI StdinInfo(LPVOID param)
{
struct msg msg;
TCHAR buf[1280] = { 0 };
parameters* p = (parameters*)param;
while (TRUE)
{
_fgetts(buf, 1280, stdin);
while (_tcslen(buf) > 0 && buf[_tcslen(buf) - 1] == TEXT('\n'))
buf[_tcslen(buf) - 1] = TEXT('\0');
buf[128] = TEXT('\0');
if (!_tcscmp(buf, TEXT("stop")))
{
//printf("Terminating...\n");
msg.isEmpty = 0;
msg.type = STOP;
_tcscpy(msg.message, buf);
_tcscpy(msg.nickName, p->nickName);
SendMessage(p, &msg);
break;
}
else if (!_tcscmp(buf, TEXT("exit")))
{
msg.isEmpty = 0;
msg.type = DISCONNECT;
_tcscpy(msg.message, buf);
_tcscpy(msg.nickName, p->nickName);
SendMessage(p, &msg);
break;
}
msg.isEmpty = 0;
msg.type = MESSAGE;
_tcscpy(msg.message, buf);
_tcscpy(msg.nickName, p->nickName);
_tprintf(TEXT(" IN TREAD %s %s\n"), msg.message, p->nickName);
SendMessage(p, &msg);
}
return 0;
}

kprobe, function scheduling - processor lockup - Linux kernel

I've a function I wrote in order to run a given function on all processors. It works perfectly well in all cases except the following case:
When I try to use it within a kprobe that I registered.
Here's some code:
static DEFINE_MUTEX(entryMutex);
static struct kretprobe my_kprobe = {
.entry_handler = (kprobe_opcode_t *) NULL,
.handler = (kprobe_opcode_t *) process_entry_callback,
.maxactive = 1000,
.data_size = 0
};
static int driver_init(void)
{
my_kprobe.kp.addr = (kprobe_opcode_t*)kallsyms_lookup_name("sys_execve");
if ((ret = register_kretprobe(&my_kprobe)) < 0)
return -1;
return 0;
}
void foo(void* nothing)
{
printk("In foo\n");
}
static int process_entry_callback(struct kretprobe_instance* instance, struct pt_regs* regs)
{
mutex_lock(&entryMutex);
for(int i = 0; i < 4; ++i) // assumes there are 4 processors
run_func(foo, NULL, i);
mutex_unlock(&entryMutex);
return 0;
}
void run_func_wrap(struct function_data* data)
{
data->func(data->context);
wake_up_process(data->waiting_task);
*(data->condition) = TRUE;
}
void run_func(SCHEDULED_FUNC func, void *context, int processor)
{
struct function_data data;
struct task_struct* th;
BOOLEAN condition = FALSE;
wait_queue_head_t queue;
init_waitqueue_head(&queue);
data.func = func;
data.waiting_task = current;
data.context = context;
data.condition = &condition;
th = kthread_create(sched_func_wrap, &data, "th");
kthread_bind(th, processor);
wake_up_process(th);
wait_event(queue, condition);
}
F
After the call to 'run_func' in process_entry_callback I can no longer run any programs. Every time I start a new program it just stuck. After a while I get 'processor lockup' warning in the system log.
I suspect that it has something to do with the IRQ levels.
Any suggestions ?
EDIT:
It also happens when using the following function:
smp_call_function_single
which can be found in smp.c # the Linux kernel source code.
instead of my function:
run_func

OpenSSL i2d_ECPrivateKey() crashes

I have the following program. It successfully obtains the raw 32 byte EC private key data and then creates a EC_KEY from it. But i2d_ECPrivateKey fails to give the size of the DER encoded private key, as it crashes. Does anyone know why and how to fix this?
#include "CBWIF.h"
#include <openssl/ssl.h>
int main(int argc, char * argv[]) {
CBWIF wif;
if (argc != 2)
return EXIT_FAILURE;
// Decode WIF string
CBByteArray str;
CBInitByteArrayFromString(&str, argv[1], false);
CBInitWIFFromString(&wif, &str, false);
CBDestroyByteArray(&str);
// Get key
uint8_t key[32];
CBWIFGetPrivateKey(&wif, key);
CBDestroyWIF(&wif);
// Create OpenSSL key
EC_KEY * eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
BIGNUM * bn = BN_bin2bn(key, CB_PRIVKEY_SIZE, NULL);
if (!EC_KEY_set_private_key(eckey, bn))
return EXIT_FAILURE;
// Convert key to DER format
int len = i2d_ECPrivateKey(eckey, NULL); // <-- CRASH HERE
unsigned char derkey[len];
i2d_ECPrivateKey(eckey, (unsigned char **)&derkey);
EC_KEY_free(eckey);
// Encode DER key as hex
char out[len*2+1];
CBBytesToString(derkey, 0, len, out, false);
// Print to stdout
puts(out);
return EXIT_SUCCESS;
}
CB_PRIVKEY_SIZE is 32. I verified that the key data from CBWIFGetPrivateKey is correct. The program crashes with the following stacktrace:
#0 0x00007ffff766cb03 in EC_POINT_point2oct () from /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#1 0x00007ffff7658124 in i2d_ECPrivateKey () from /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#2 0x0000000000400bf6 in main (argc=2, argv=0x7fffffffe038) at examples/WIF2DER.c:46
The reason is that you cannot run i2d_ECPrivateKey without setting a public key, probably due to a bug in OpenSSL. I generated the public key and solved a few other issues an now the program works:
#include "CBWIF.h"
#include <openssl/ssl.h>
int main(int argc, char * argv[]) {
CBWIF wif;
if (argc != 2)
return EXIT_FAILURE;
// Decode WIF string
CBByteArray str;
CBInitByteArrayFromString(&str, argv[1], false);
CBInitWIFFromString(&wif, &str, false);
CBDestroyByteArray(&str);
// Get key
uint8_t key[32];
CBWIFGetPrivateKey(&wif, key);
CBDestroyWIF(&wif);
// Create OpenSSL key
EC_KEY * eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
BIGNUM * bn = BN_bin2bn(key, CB_PRIVKEY_SIZE, NULL);
if (!EC_KEY_set_private_key(eckey, bn))
return EXIT_FAILURE;
// Create public key as OpenSSL cannot do this easily
EC_GROUP * group = EC_GROUP_new_by_curve_name(NID_secp256k1);
EC_POINT * point = EC_POINT_new(group);
BN_CTX * ctx = BN_CTX_new();
EC_POINT_mul(group, point, bn, NULL, NULL, ctx);
BN_CTX_free(ctx);
EC_GROUP_free(group);
BN_free(bn);
if (!EC_KEY_set_public_key(eckey, point))
return EXIT_FAILURE;
EC_POINT_free(point);
// Check the key
if (!EC_KEY_check_key(eckey))
return EXIT_FAILURE;
// Convert key to DER format
int len = i2d_ECPrivateKey(eckey, NULL);
unsigned char derkey[len];
unsigned char * derkeyPtr = derkey;
i2d_ECPrivateKey(eckey, &derkeyPtr);
// Freeing the EC_KEY here crashes for some reason???
// Encode DER key as hex
char out[len*2+1];
CBBytesToString(derkey, 0, len, out, false);
// Print to stdout
puts(out);
return EXIT_SUCCESS;
}
Here's how OpenSSL uses it in <openssl src/crypto/ec/ec_ameth.c. All the other similar uses in the library utilize i2d_ECPrivateKey_bio. Also, you might take a quick look at how the OPENSSL_EC_NAMED_CURVE flag is used with V_ASN1_OBJECT.
unsigned char *ep, *p;
int eplen, ptype;
unsigned int tmp_flags, old_flags;
...
old_flags = EC_KEY_get_enc_flags(ec_key);
tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
...
eplen = i2d_ECPrivateKey(ec_key, NULL);
if (!eplen)
{
EC_KEY_set_enc_flags(ec_key, old_flags);
ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
return 0;
}
ep = (unsigned char *) OPENSSL_malloc(eplen);
if (!ep)
{
EC_KEY_set_enc_flags(ec_key, old_flags);
ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
return 0;
}
p = ep;
if (!i2d_ECPrivateKey(ec_key, &p))
{
EC_KEY_set_enc_flags(ec_key, old_flags);
OPENSSL_free(ep);
ECerr(EC_F_ECKEY_PRIV_ENCODE, ERR_R_EC_LIB);
return 0;
}
...
Also take a look at Avoid a NULL dereference in i2d_ECPrivateKey() when an EC_KEY lacks the public key member from OpenBSD's LibReSSL project.

Read certificate files from memory instead of a file using OpenSSL

I have a server which would listen on HTTPS using OpenSSL. For this, I have to provide the certificate to use. However, the current implementation uses a filename to be provided to the OpenSSL API.
I want the certificate information to be read from memory, so that I don't have to ship the certificate file opening. I tried to google, but I didn't come up with any options.
Is is possible? If so, how do I read certificate files from memory instead of a file using OpenSSL?
EDIT: The following was moved from the comments to the question.
// CURRENT
void start_server()
{
const char *fileName = "cert_and_key.pem";
set_server_ssl_file(fileName);
}
set_server_ssl_file(const char *fileName)
{
//initialize context
SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM);
}
//REQUIRED
void start_server()
{
const char *cert = "--BEGIN CERTIFICATE--............";
const char *key = "--BEGIN RSA PRIVATE KEY--.......";
set_server_ssl_options(cert, key);
}
set_server_ssl_options(const char *cert, const char *key)
{
//IMPLEMENTATION REQUIRED
}
The following code did the job for me:
SSL_CTX *CTX;
X509 *cert = NULL;
RSA *rsa = NULL;
BIO *cbio, *kbio;
const char *cert_buffer = "";
const char *key_buffer = "";
cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
cert = PEM_read_bio_X509(cbio, NULL, 0, NULL);
assert(cert != NULL);
SSL_CTX_use_certificate(CTX, cert);
kbio = BIO_new_mem_buf((void*)key_buffer, -1);
rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL);
assert(rsa != NULL);
SSL_CTX_use_RSAPrivateKey(CTX, rsa);
The other snippets will only load one certificate. The content of files like http://curl.haxx.se/ca/cacert.pem that contain a lot of different certificates need a new approach. This is adapted from openssl 1.0.1p (mostly openssl-1.0.1p\crypto\x509\by_file.c, char* buf contains the content of a *.pem file, ctx is a boost::asio::ssl::context), add error handling on your own:
BIO *cbio = BIO_new_mem_buf((void*)buf, (int)length);
X509_STORE *cts = SSL_CTX_get_cert_store(ctx.native_handle());
if(!cts || !cbio)
return false;
X509_INFO *itmp;
int i, count = 0, type = X509_FILETYPE_PEM;
STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
if (!inf)
{
BIO_free(cbio);//cleanup
return false;
}
//itterate over all entries from the pem file, add them to the x509_store one by one
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
itmp = sk_X509_INFO_value(inf, i);
if (itmp->x509) {
X509_STORE_add_cert(cts, itmp->x509);
count++;
}
if (itmp->crl) {
X509_STORE_add_crl(cts, itmp->crl);
count++;
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free); //cleanup
BIO_free(cbio);//cleanup
unsigned char *cert_data = (....);
int cert_len = (....);
X509 *cert = d2i_X509(NULL, &cert_data, cert_len);
SSL_CTX_use_certificate(ctx, cert);
unsigned char *pkey_data = /* ... */;
int pkey_len = /* ... */;
RSA *pkey = d2i_RSAPrivateKey(NULL, &pkey_data, pkey_len);
SSL_CTX_use_RSAPrivateKey(ctx, pkey);
Don't forget & before cert_data and pkey_data - and note that OpenSSL modifies these pointers.
There is another response that uses X509_STORE_add_cert, which is up-voted but incorrect. That answer is a way to do SSL_CTX_load_verify_locations in memory, but does not load the server certificate chain. Replies to that comment also indicate that it does not work.
The following code is a load-from-memory implementation of SSL_CTX_use_certificate_chain_file based on the implementation of that function in OpenSSL:
bool load_cert_chain_from_shared_mem(SSL_CTX *context, const char *cert_buffer)
{
BIO *cbio = BIO_new_mem_buf((void*)cert_buffer, -1);
if (!cbio)
return false;
X509_INFO *itmp;
int i, count = 0, type = X509_FILETYPE_PEM;
STACK_OF(X509_INFO) *inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
if (!inf)
{
BIO_free(cbio);
return false;
}
/* Iterate over contents of the PEM buffer, and add certs. */
BOOL first = TRUE;
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
itmp = sk_X509_INFO_value(inf, i);
if (itmp->x509)
{
/* First cert is server cert. Remaining, if any, are intermediate certs. */
if (first)
{
first = FALSE;
/*
* Set server certificate. Note that this operation increments the
* reference count, which means that it is okay for cleanup to free it.
*/
if (!SSL_CTX_use_certificate(context, itmp->x509))
goto Error;
if (ERR_peek_error() != 0)
goto Error;
/* Get ready to store intermediate certs, if any. */
SSL_CTX_clear_chain_certs(context);
}
else
{
/* Add intermediate cert to chain. */
if (!SSL_CTX_add0_chain_cert(context, itmp->x509))
goto Error;
/*
* Above function doesn't increment cert reference count. NULL the info
* reference to it in order to prevent it from being freed during cleanup.
*/
itmp->x509 = NULL;
}
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
return true;
Error:
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
return false;
}

Resources