OpenSSL gost engine code example - c

Can anybody help me with example of usage of OpenSSL gost engine. I have to sign data using GOST R 34.10-2001 signature algorithm but can't find any working examples or documention.
BTW if I'm not going to use that OpenSSL command line utility is there any sense in modifying that openssl.cnf file? If not how do I load engine in code? And what compile flags are needed to build OpenSSL with static gost engine?
Thanks in advance.
----Solution----
Finally the following verifies successfully for me:
ENGINE * LoadEngine()
{
ENGINE *e = NULL;
ENGINE_load_gost();
e = ENGINE_by_id("gost");
if(!e)
{
printf("Filed to get structural reference to engine\n");
}
if(!ENGINE_init(e))
{
ENGINE_free(e);
printf("Failed to get functional reference to engine\n");
}
ENGINE_set_default(e, ENGINE_METHOD_ALL);
OpenSSL_add_all_algorithms();
return e;
}
EVP_PKEY * GenerateKeys(ENGINE *e)
{
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, e);
EVP_PKEY_paramgen_init(ctx);
EVP_PKEY_CTX_ctrl(ctx,
NID_id_GostR3410_2001,
EVP_PKEY_OP_PARAMGEN,
EVP_PKEY_CTRL_GOST_PARAMSET,
NID_id_GostR3410_2001_CryptoPro_A_ParamSet,
NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_keygen(ctx, &pkey);
EVP_PKEY_CTX_free(ctx);
return pkey;
}
int main()
{
ENGINE *e = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
unsigned char msg[] = "this is a test message";
Binary hash(32);
SHA256_Calc(msg, sizeof(msg), &hash[0]);
size_t siglen = 0;
int status = 0;
e = LoadEngine();
pkey = GenerateKeys(e);
ctx = EVP_PKEY_CTX_new(pkey, e);
if(ctx == NULL)
{
printf("Failed to create context\n");
return -1;
}
EVP_PKEY_sign_init(ctx);
status = EVP_PKEY_sign_init(ctx);
if(status != 1)
{
printf("Failed to init signing context\n");
return -1;
}
status = EVP_PKEY_sign(ctx, NULL, &siglen, &hash[0], hash.size());
if(status != 1)
{
printf("Failed to get signature length\n");
return -1;
}
Binary signature(siglen);
status = EVP_PKEY_sign(ctx, &signature[0], &siglen, &hash[0], hash.size());
if(status != 1)
{
printf("Failed to sign a message\n");
return -1;
}
EVP_PKEY_verify_init(ctx);
bool result = EVP_PKEY_verify(ctx, &signature[0], siglen, &hash[0], hash.size());
printf("%s\n", result ? "SUCCESS" : "FAILURE");
ENGINE_cleanup();
}

Related

Translate OpenSSL RSA encryption to GnuTLS

I am attempting to translate the following code from OpenSSL to GnuTLS for licencing reasons:
BIO *bioKey = BIO_new(BIO_s_mem());
if (!bioKey)
{
DEBUG_ERROR("failed to allocate bioKey");
spice_disconnect_channel(channel);
return false;
}
BIO_write(bioKey, reply.pub_key, SPICE_TICKET_PUBKEY_BYTES);
EVP_PKEY *rsaKey = d2i_PUBKEY_bio(bioKey, NULL);
RSA *rsa = EVP_PKEY_get1_RSA(rsaKey);
char enc[RSA_size(rsa)];
if (RSA_public_encrypt(
strlen(spice.password) + 1,
(uint8_t*)spice.password,
(uint8_t*)enc,
rsa,
RSA_PKCS1_OAEP_PADDING
) <= 0)
{
DEBUG_ERROR("rsa public encrypt failed");
spice_disconnect_channel(channel);
EVP_PKEY_free(rsaKey);
BIO_free(bioKey);
return false;
}
ssize_t rsaSize = RSA_size(rsa);
EVP_PKEY_free(rsaKey);
BIO_free(bioKey);
So far I have come up with the following but it seems the output is not in the correct format (RSA_PKCS1_OEAP_PADDING)
const gnutls_datum_t pubData =
{
.data = (void *)reply.pub_key,
.size = SPICE_TICKET_PUBKEY_BYTES
};
gnutls_pubkey_t pubkey;
if (gnutls_pubkey_init(&pubkey) < 0)
{
spice_disconnect_channel(channel);
DEBUG_ERROR("gnutls_pubkey_init failed");
return false;
}
if (gnutls_pubkey_import(pubkey, &pubData, GNUTLS_X509_FMT_DER) < 0)
{
gnutls_pubkey_deinit(pubkey);
spice_disconnect_channel(channel);
DEBUG_ERROR("gnutls_pubkey_import failed");
return false;
}
const gnutls_datum_t input =
{
.data = (void *)spice.password,
.size = strlen(spice.password) + 1
};
gnutls_datum_t out;
if (gnutls_pubkey_encrypt_data(pubkey, 0, &input, &out) < 0)
{
gnutls_pubkey_deinit(pubkey);
spice_disconnect_channel(channel);
DEBUG_ERROR("gnutls_pubkey_encrypt_data failed");
return false;
}
const char *enc = (char *)out.data;
const unsigned int rsaSize = out.size;
I am no expert with encryption or these libraries, so please be kind.
GnuTLS does not support ES-OEAP at all. gnutls_pubkey_encrypt_data produces PKCS#1 padded data and can not be used.
The solution is to avoid GnuTLS entirely and perform the encryption manually using nettle and libgmp. I based my solution on the example in FreeTDS:
http://www.freetds.org/reference/a00351_source.html
This implements an OEAP padding function and uses GMP to perform the RSA encryption.

Decrypting an AES-encrypted message with an RSA-encrypted key with EVP tool

For industrial purposes, I want to decrypt an AES-encrypted message with an RSA-encrypted key in C. At first, I thought doing it step-by-step by first, using OpenSSL libcrypto library, by first RSA decoding the key then AES decoding the data.
I have found out that EVP tools were commonly seen as a better way to do this since it actually does what the low-levels functions do but correctly.
Here is what I see the flow of the program :
Initialize OpenSSL;
Read and store the RSA private key;
Initialize the decryption by specifying the decryption algorithm (AES) and the private key;
Update the decryption by giving the key, the data, the key and their length
Finally decrypt the data and return it.
I have been a lot confused by the fact that so far we do not intend to use any IV or ADD (although IV might come up later in the project). I have followed this guide it is not very clear and does not fit the way I use EVP.
So here is my actual code :
#include <openssl/evp.h>
#include <openssl/conf.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include "openssl\applink.c"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
const char PRIVATE_KEY_PATH[] = "C:/Users/Local_user/privateKey.pem";
EVP_PKEY* initializePrivateKey(void)
{
FILE* privateKeyfile;
if ((privateKeyfile = fopen(PRIVATE_KEY_PATH, "r")) == NULL) // Check PEM file opening
{
perror("Error while trying to access to private key.\n");
return NULL;
}
RSA *rsaPrivateKey = RSA_new();
EVP_PKEY *privateKey = EVP_PKEY_new();
if ((rsaPrivateKey = PEM_read_RSAPrivateKey(privateKeyfile, &rsaPrivateKey, NULL, NULL)) == NULL) // Check PEM file reading
{
fprintf(stderr, "Error loading RSA Private Key File.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
if (!EVP_PKEY_assign_RSA(privateKey, rsaPrivateKey))
{
fprintf(stderr, "Error when initializing EVP private key.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
return privateKey;
}
const uint8_t* decodeWrappingKey(uint8_t const* data, const size_t data_len, uint8_t const* wrappingKey, const size_t wrappingKey_len)
{
// Start Decryption
EVP_CIPHER_CTX *ctx;
if (!(ctx = EVP_CIPHER_CTX_new())) // Initialize context
{
fprintf(stderr, "Error when initializing context.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
EVP_PKEY *privateKey = initializePrivateKey();
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, privateKey, NULL)) // Initialize decryption
{
fprintf(stderr, "Error when initializing decryption.\n");
ERR_print_errors_fp(stderr);
return NULL;
}
uint8_t* res;
if ((res = calloc(data_len, sizeof(uint8_t))) == NULL) // Check memory allocating
{
perror("Memory allocating error ");
return NULL;
}
puts("Initialization done. Decoding..\n");
size_t res_len = 0;
if (1 != EVP_DecryptUpdate(ctx, res, &res_len, data, data_len))
{
fprintf(stderr, "Error when preparing decryption.\n");
ERR_print_errors_fp(stderr);
}
if (1 != EVP_DecryptFinal_ex(ctx, res, &res_len))
{
fprintf(stderr, "Error when decrypting.\n");
ERR_print_errors_fp(stderr);
}
return res;
}
void hexToBytes(uint8_t *des, char const *source, const size_t size) {
for (int i = 0; i < size - 1; i += 2)
sscanf(source + i, "%02x", des + (i / 2));
}
int main(void) {
char const *strWrap = "5f82c48f85054ef6a3b2621819dd0e969030c79cc00deb89........";
char const *strData = "ca1518d44716e3a4588af741982f29ad0a3e7a8d67.....";
uint8_t *wrap = calloc(strlen(strWrap), sizeof(uint8_t));
hexToBytes(wrap, strWrap, strlen(strWrap)); // Converts string to raw data
uint8_t *data = calloc(strlen(strData), sizeof(uint8_t));
hexToBytes(data, strData, strlen(strData));
/* Load the human readable error strings for libcrypto */
ERR_load_crypto_strings();
/* Load all digest and cipher algorithms */
OpenSSL_add_all_algorithms();
/* Load config file, and other important initialisation */
OPENSSL_config(NULL);
const uint8_t *res = decodeWrappingKey(data, strlen(strData) / 2, wrap, strlen(strWrap) / 2);
if (res == NULL)
return 1;
return 0;
}
My output is the following one :
Initialization done. Decoding..
Error when preparing decryption.
Error when decrypting.
Obviously it fails when updating and finalising the decryption but I can't figure out why and the ERR_print_errors_fp(stderr); which had always worked for me so far seems to be mute.
Here is a complete working example of how you can encrypt a key using RSA, and encrypt a message using that key using AES, followed by the subsequent decryption of those things. It assumes AES-256-CBC is being used. If you want to use AES-256-GCM instead then you will need to make some changes to get and set the tag (ask me if you need some pointers on how to do this). It also assumes that the RSA encryption is done with PKCS#1 padding (which is all that the EVP_Seal* APIs support). If you need some other kind of padding then you will need to use a different method. Finally it assumes you are using OpenSSL 1.1.0. If you are using 1.0.2 then some changes will probably be necessary (at least you will need to explicitly init and de-init the library - that isn't required in 1.1.0).
The code reads the RSA private and public keys from files called privkey.pem and pubkey.pem which are in the current working directory. I generated these files like this:
openssl genrsa -out privkey.pem 2048
openssl rsa -in privkey.pem -pubout -out pubkey.pem
I've tested this on Linux only. The code is as follows:
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int envelope_seal(EVP_PKEY *pub_key, unsigned char *plaintext,
int plaintext_len, unsigned char **encrypted_key,
int *encrypted_key_len, unsigned char **iv,
int *iv_len, unsigned char **ciphertext,
int *ciphertext_len)
{
EVP_CIPHER_CTX *ctx;
int len, ret = 0;
const EVP_CIPHER *type = EVP_aes_256_cbc();
unsigned char *tmpiv = NULL, *tmpenc_key = NULL, *tmpctxt = NULL;
if((ctx = EVP_CIPHER_CTX_new()) == NULL)
return 0;
*iv_len = EVP_CIPHER_iv_length(type);
if ((tmpiv = malloc(*iv_len)) == NULL)
goto err;
if ((tmpenc_key = malloc(EVP_PKEY_size(pub_key))) == NULL)
goto err;
if ((tmpctxt = malloc(plaintext_len + EVP_CIPHER_block_size(type)))
== NULL)
goto err;
if(EVP_SealInit(ctx, type, &tmpenc_key, encrypted_key_len, tmpiv, &pub_key,
1) != 1)
goto err;
if(EVP_SealUpdate(ctx, tmpctxt, &len, plaintext, plaintext_len) != 1)
goto err;
*ciphertext_len = len;
if(EVP_SealFinal(ctx, tmpctxt + len, &len) != 1)
goto err;
*ciphertext_len += len;
*iv = tmpiv;
*encrypted_key = tmpenc_key;
*ciphertext = tmpctxt;
tmpiv = NULL;
tmpenc_key = NULL;
tmpctxt = NULL;
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
free(tmpiv);
free(tmpenc_key);
free(tmpctxt);
return ret;
}
int envelope_open(EVP_PKEY *priv_key, unsigned char *ciphertext,
int ciphertext_len, unsigned char *encrypted_key,
int encrypted_key_len, unsigned char *iv,
unsigned char **plaintext, int *plaintext_len)
{
EVP_CIPHER_CTX *ctx;
int len, ret = 0;
unsigned char *tmpptxt = NULL;
if((ctx = EVP_CIPHER_CTX_new()) == NULL)
return 0;
if ((tmpptxt = malloc(ciphertext_len)) == NULL)
goto err;
if(EVP_OpenInit(ctx, EVP_aes_256_cbc(), encrypted_key, encrypted_key_len,
iv, priv_key) != 1)
return 0;
if(EVP_OpenUpdate(ctx, tmpptxt, &len, ciphertext, ciphertext_len) != 1)
return 0;
*plaintext_len = len;
if(EVP_OpenFinal(ctx, tmpptxt + len, &len) != 1)
return 0;
*plaintext_len += len;
*plaintext = tmpptxt;
tmpptxt = NULL;
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
free(tmpptxt);
return ret;
}
int main(void)
{
EVP_PKEY *pubkey = NULL, *privkey = NULL;
FILE *pubkeyfile, *privkeyfile;
int ret = 1;
unsigned char *iv = NULL, *message = "Hello World!\n";
unsigned char *enc_key = NULL, *ciphertext = NULL, *plaintext = NULL;
int iv_len = 0, enc_key_len = 0, ciphertext_len = 0, plaintext_len = 0, i;
if ((pubkeyfile = fopen("pubkey.pem", "r")) == NULL) {
printf("Failed to open public key for reading\n");
goto err;
}
if ((pubkey = PEM_read_PUBKEY(pubkeyfile, &pubkey, NULL, NULL)) == NULL) {
fclose(pubkeyfile);
goto err;
}
fclose(pubkeyfile);
if ((privkeyfile = fopen("privkey.pem", "r")) == NULL) {
printf("Failed to open private key for reading\n");
goto err;
}
if ((privkey = PEM_read_PrivateKey(privkeyfile, &privkey, NULL, NULL))
== NULL) {
fclose(privkeyfile);
goto err;
}
fclose(privkeyfile);
if (!envelope_seal(pubkey, message, strlen(message), &enc_key, &enc_key_len,
&iv, &iv_len, &ciphertext, &ciphertext_len))
goto err;
printf("Ciphertext:\n");
for (i = 0; i < ciphertext_len; i++)
printf("%02x", ciphertext[i]);
printf("\n");
printf("Encrypted Key:\n");
for (i = 0; i < enc_key_len; i++)
printf("%02x", enc_key[i]);
printf("\n");
printf("IV:\n");
for (i = 0; i < iv_len; i++)
printf("%02x", iv[i]);
printf("\n");
if (!envelope_open(privkey, ciphertext, ciphertext_len, enc_key,
enc_key_len, iv, &plaintext, &plaintext_len))
goto err;
plaintext[plaintext_len] = '\0';
printf("Plaintext: %s\n", plaintext);
ret = 0;
err:
if (ret != 0) {
printf("Error\n");
ERR_print_errors_fp(stdout);
}
EVP_PKEY_free(pubkey);
EVP_PKEY_free(privkey);
free(iv);
free(enc_key);
free(ciphertext);
free(plaintext);
return ret;
}
Your key is encrypted with RSA, so you will decrypt it with RSA APIs like RSA_private_decrypt first, not with EVP* APIs.
Once you get key decrypted you need to use it with (EVP*) APIs to decrypt the data with AES.

Creating a self-signed x509 certificate using OpenSSL with the TPM engine programatically

What are the actual steps of creating a self-signed x509 certificate using OpenSSL with the TPM engine? X509_sign(cert, key, EVP_sha1()) seems to fail every single time for me.
The error code i got from X509_sign is:
Error code 2147913847
Using ERR_print_errors_fp I got:
3064825040:error:0D0DC006:asn1 encoding routines:func(220):EVP lib:a_sign.c:314:
What i did was:
1) create a key using the TPM
2) write the key blob into a file
if ((outb = BIO_new_file(KEY_FILENAME, "w")) == NULL) {
fprintf(stderr, "Error opening file for write: %s\n", KEY_FILENAME);
Tspi_Context_CloseObject(tpm.hContext, hKey);
Tspi_Context_Close(tpm.hContext);
exit(-1);
}
blob_str = ASN1_OCTET_STRING_new();
if (!blob_str) {
fprintf(stderr, "Error allocating ASN1_OCTET_STRING\n");
Tspi_Context_CloseObject(tpm.hContext, hKey);
Tspi_Context_Close(tpm.hContext);
exit(-1);
}
ASN1_STRING_set(blob_str, blob, blob_size);
asn1_len = i2d_ASN1_OCTET_STRING(blob_str, &blob_asn1);
PEM_write_bio(outb, "TSS KEY BLOB", "", blob_asn1, asn1_len);
BIO_free(outb);
3) Use the TPM engine to read the file that was created in (2) and change it to a EVP_PKEY
const char *engineId = "tpm";
ENGINE *e;
EVP_PKEY *key;
ENGINE_load_builtin_engines();
e = ENGINE_by_id(engineId);
if (!e) { // Engine not available
ERR_print_errors_fp(stderr);
ERR("ENGINE_by_id failed.");
return NULL;
}
if (!ENGINE_init(e)) { // Engine couldn't initialise
ERR_print_errors_fp(stderr);
ERR("ENGINE_init failed.");
ENGINE_free(e);
ENGINE_finish(e);
return NULL;
}
if (!ENGINE_set_default_RSA(e) || !ENGINE_set_default_RAND(e)) {
/* This should only happen when 'e' can't initialise, but the previous
* statement suggests it did. */
ERR_print_errors_fp(stderr);
ERR("ENGINE_init failed.");
ENGINE_free(e);
ENGINE_finish(e);
return NULL;
}
ENGINE_ctrl_cmd(e, "PIN", 0, SRK_PASSWORD, NULL, 0);
ENGINE_free(e);
if ((key = ENGINE_load_private_key(e, fileName, NULL, NULL)) == NULL) {
ERR_print_errors_fp(stderr);
ERR("Couldn't load TPM key \"%s\" from file.", fileName);
return NULL;
}
ENGINE_finish(e);
e = NULL;
4) Generate a cert using the EVP_PKEY created in (3)
X509 *cert;
X509_NAME *name = NULL;
FILE * fp = NULL;
// pk = key;
cert = X509_new();
X509_set_version(cert, 2);
// serial = M_ASN1_INTEGER_new();
ASN1_INTEGER_set(X509_get_serialNumber(cert), 0);
X509_gmtime_adj(X509_get_notBefore(cert), 0);
X509_gmtime_adj(X509_get_notAfter(cert), (long)60 * 60 * 24 * CERT_VALIDITY);
X509_set_pubkey(cert, key);
name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char *)"SG", -1, -1, 0); //country
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, (const unsigned char *)"SG", -1, -1, 0); //state
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, (const unsigned char *)"Singapore", -1, -1, 0); //locality
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (const unsigned char *)"org", -1, -1, 0); //organisation
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, (const unsigned char *)"unit", -1, -1, 0); //organisational unit
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char *)"name", -1, -1, 0); //common name
X509_set_issuer_name(cert, name); // Its self signed so set the issuer name to be the same as the subject.
PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
PEM_write_PUBKEY(stdout, key);
if (!X509_sign(cert, key, EVP_sha1())) {
printf("Error signing certificate\n");
printf("Error code %lu\n", ERR_get_error());
ERR_print_errors_fp(stderr);
return;
} else {
PEM_write_X509(stdout, cert);
fp = fopen("x509.cert", "wb");
if (fp != NULL) {
i2d_X509_fp(fp, cert);
}
fclose(fp);
X509_free(cert);
}
Am i doing anything wrongly? Please help, I cant seem to find much documentation on using OpenSSL with the TPM engine. Thanks.

Forcing global headers in LibAV

I'm trying to write a C program using LibAV that takes input video from a webcam and saves it as an H264 MP4 file. I'm modifying a working program that saves .ppm frames from the webcam. I'm unable to convert the AVPackets so that they may be written, though--specifically, avformat_write_header() is failing, with the messages
[mp4 # 0050c000] Codec for stream 0 does not use global headers but container format requires global headers
[mp4 # 0050c000] Could not find tag for codec none in stream #0, codec not currently supported in container
The call is apparently returning error -22, but I can find no place where that error code is actually explained. How can I force avformat_write_header() to add in global headers when it's trying to write the MP4? Code below; some of it is adapted from this question, but I'm trying to adapt it from an input video file to a webcam.
int _tmain(int argc, _TCHAR* argv[])
{
AVInputFormat *inputFormat = NULL;
AVDictionary *inputDictionary= NULL;
AVFormatContext *inputFormatCtx = NULL;
AVFormatContext *outputFormatCtx = NULL;
AVCodecContext *inputCodecCtxOrig = NULL;
AVCodecContext *inputCodecCtx = NULL;
AVCodecContext *outputCodecCtx;
AVCodec *inputCodec = NULL;
AVCodec *outputCodec = NULL;
AVStream *stream = NULL;
AVIOContext *avioContext = NULL;
avcodec_register_all();
av_register_all();
avdevice_register_all();
av_dict_set(&inputDictionary, "Logitech HD Pro Webcam C920", "video", 0);
avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, "output.mp4");
avio_open(&avioContext, "output.mp4", AVIO_FLAG_WRITE);
outputFormatCtx->pb = avioContext;
stream = avformat_new_stream(outputFormatCtx, outputCodec);
inputFormat = av_find_input_format("dshow");
int r = avformat_open_input(&inputFormatCtx, "video=Logitech HD Pro Webcam C920", inputFormat, &inputDictionary);
if (r != 0) {
fprintf(stderr, "avformat_open_input() failed with error %d!\n", r);
return -1; }
r = avformat_find_stream_info(inputFormatCtx, NULL);
if (r != 0) {
fprintf(stderr, "avformat_find_stream_info() failed!\n");
return -1; }
av_dump_format(inputFormatCtx, 0, "video=Logitech HD Pro Webcam C920", 0);
unsigned int i;
int videoStream;
videoStream = -1;
for (i = 0; i < inputFormatCtx->nb_streams; i++) {
if (inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO {
videoStream = i;
break; }
}
if (videoStream == -1)
{ return -1; }
inputCodecCtxOrig = inputFormatCtx->streams[videoStream]->codec;
inputCodec = avcodec_find_decoder(inputCodecCtxOrig->codec_id);
if (inputCodec == NULL) {
fprintf(stderr, "avcodec_find_decoder() failed!\n");
return -1; }
else { printf("Supported codec!\n"); }
inputCodecCtx = avcodec_alloc_context3(inputCodec);
if (inputCodecCtx == NULL) {
fprintf(stderr, "avcodec_alloc_context3() failed!\n");
return -1; }
if (avcodec_copy_context(inputCodecCtx, inputCodecCtxOrig) != 0) {
fprintf(stderr, "avcodec_copy_context() failed!\n");
return -1; }
if (avcodec_open2(inputCodecCtx,inputCodec,&inputDictionary) < 0) {
fprintf(stderr, "avcodec_open2() failed!\n");
return -1; }
outputFormatCtx->oformat = av_guess_format(NULL, "output.mp4", NULL);
outputFormatCtx->oformat->flags |= AVFMT_GLOBALHEADER;
outputCodecCtx = avcodec_alloc_context3(outputCodec);
avcodec_copy_context(outputCodecCtx, inputCodecCtx);
outputCodec = inputCodec;
avcodec_open2(outputCodecCtx, outputCodec, NULL);
AVPacket packet;
printf("foo\n");
int errnum = avformat_write_header(outputFormatCtx, &inputDictionary);
printf("bar %d\n", errnum);
while(av_read_frame(inputFormatCtx, &packet)>=0) {
av_interleaved_write_frame(outputFormatCtx, &packet);
av_free_packet(&packet);
}
avcodec_close(inputCodecCtx);
avcodec_close(inputCodecCtxOrig);
avformat_close_input(&inputFormatCtx);
return 0;
}
How can I force avformat_write_header() to add in global headers
Global headers are written by the encoder, later the muxer reads them from the codec's extra_data field. So you should set this flag in the codec's context, before you call avcodec_open2().
outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
[mp4 # 0050c000] Could not find tag for codec none in stream #0, codec
not currently supported in container
You can try to setup the encoder explicitly (i.e. manually), or copy the codeccontext from original input codeccontext.
outputCodec = av_codec_find_encoder(AV_CODEC_ID_H264);
if(!outputCodec) return -1; //no encoder found
outputCodecCtx = avcodec_alloc_context3(outputCodec);
avcodec_copy_context(outputCodecCtx, inputCodecCtxOrig); //copy from orig
//You have to make sure each field is populated correctly
//with debugger or assertations
assert(outputCodecCtx->codec_id == AV_CODEC_ID_H264); //etc
outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if(avcodec_open2(outputCodecCtx, outputCodec, NULL) <0) return -1;

event_new() function fails on hpux itanium

I'm trying to debug a code that is using a libevent library. In that library, there is a function event_new that is suppose to create an event_cb. Somehow after I dispatch the event base, the event_cb cannot be called or accessed. This problem only happens on hpux itanium. This code works on hpux pa-risc, Redhat, AIX, and Solaris. Is there any certain thing that need to be set?
This is part of the code
int ttypread (int fd, Header *h, char **buf)
{
int c,k;
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
log_debug("inside ttypread");
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
log_debug("from user_data, fd = %d",user_data.fd); //the log_debug is a debugging function for me to check the value sent by the system. I use it to compare between each platform
log_debug("from user_data, buf = %s",user_data.buf);
log_debug("from user_data, h.len = %d",user_data.h->len);
log_debug("from user_data, h.type = %d",user_data.h->type);
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
base = event_base_new_with_config(evconfig);
if (!base) {
log_error("ttypread:event_base_new failed");
return -1;
}
const char* method; //these 3 lines are the new line edited
method = event_base_get_method(base);
log_debug("ttyread is using method = %s",method);
ev = event_new(base, fd, EV_READ|EV_PERSIST, ttypread_event_cb, &user_data);
c = event_add(ev, NULL);
log_debug("ttypread passed event_add with c value is %d",c);
in_buffer = bufferevent_socket_new(base, STDIN_FILENO, BEV_OPT_CLOSE_ON_FREE);
log_debug("ttypread passed bufferevent_socket_new");
if(in_buffer == NULL){
log_debug("problem with bufferevent_socket_new");
}
bufferevent_setcb(in_buffer, in_read_cb, NULL, in_event_cb, NULL);
bufferevent_disable(in_buffer, EV_WRITE);
bufferevent_enable(in_buffer, EV_READ);
k =event_base_dispatch(base);
log_debug("event_base have been dispatched"); //when looking at the debugging file, the other plaform will go to ttypread_event_cb function. But for hpux itanium, it stays here.
if (k == 0){
log_debug("event_base_dispatch returned 0");
} else if (k == -1){
log_debug("event_base_dispatch returned -1");
} else {
log_debug("event_base_dispatch returned 1");
}
event_base_free(base);
event_free(ev);
log_debug("finish ttypread");
log_debug("ttypread_ret will return [%d]",ttypread_ret);
return ttypread_ret;
}
void ttypread_event_cb(evutil_socket_t fd, short events, void *arg)
{
int nread;
struct timeval t;
struct user_data *user_data;
user_data = (struct user_data*)arg;
nread = 0;
log_debug("inside ttypread_event_cb");
if (events & EV_READ) {
log_debug("got events & EV_READ");
nread = ttyread(fd, user_data->h, user_data->buf);
if (nread == -1) {
ttypread_ret = -1;
event_del(ev);
event_base_loopexit(base, NULL);
} else if (nread == 0) {
if (access(input_filename, F_OK)!=0) {
log_debug("cannot access [%s]",input_filename);
tcsetattr(0, TCSANOW, &old); /* Return terminal state */
exit(EXIT_SUCCESS);
}
t.tv_sec = 0;
t.tv_usec = 250000;
select(0, 0, 0, 0, &t);
} else {
ttypread_ret = 1;
event_del(ev);
event_base_loopexit(base, NULL);
}
}
else if (events & EV_WRITE) {
log_debug("got events & EV_WRITE");
}
}
Not sure if this help. But just some info on the hpux itanium
uname -a = HP-UX hpux-ita B.11.23 U ia64
If you need any additional info or other declaration on function, just leave a comment and I will edit the question.
EDIT : i've added a function inside ttypread. Somehow for hpux itanium its returning devpoll while other platform are returning poll. Im not sure if this is the problem. But if that is so, is there any way for me to change it?
After checking the result from event_base_get_method, I found out that only on my hpux-itanium used devpoll method. This is how I solve it.
char string[8] = "devpoll";
struct user_data user_data;
struct bufferevent *in_buffer;
struct event_config *evconfig;
const char *method;
const char *devpoll;
devpoll = string;
in_buffer = NULL;
user_data.fd = fd;
user_data.h = h;
user_data.buf = buf;
evconfig = event_config_new();
if (evconfig == NULL) {
log_error("event_config_new failed");
return -1;
}
if (event_config_require_features(evconfig, EV_FEATURE_FDS)!=0) {
log_error("event_config_require_features failed");
return -1;
}
if (event_config_avoid_method(evconfig,devpoll) != 0)
{
log_error("Failed to ignore devpoll method");
}
Force the libevent to ignore using devpoll and use poll instead.

Resources