I'm trying to generate a RSA key pair in C with the following function:
int generate_key(const int bits, char* public_key_name, char* private_key_name){
    int ret = 0;
    RSA *r = NULL;
    BIGNUM *bne = NULL;
    FILE *bp_public = NULL;
    FILE* bp_private = NULL;
    
    unsigned long   e = RSA_F4;
    // 1. generate rsa key
    bne = BN_secure_new();
    ret = BN_set_word(bne,e);
    if(ret != 1){
        goto free_all;
    }
    r = RSA_new();
    ret = RSA_generate_key_ex(r, bits, bne, NULL);
    if(ret != 1){
        goto free_all;
    }
    // 2. save public key
    bp_public = fopen(public_key_name, "w+");
    ret = PEM_write_RSAPublicKey(bp_public, r);
    fclose(bp_public);
    if(ret != 1){
        goto free_all;
    }
    // 3. save private key
    bp_private = fopen(private_key_name, "w+");
    ret = PEM_write_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
    fclose(bp_private);
    // 4. free
    free_all:
    RSA_free(r);
    BN_clear_free(bne);
    return ret;
}
It works fine except for the fact that when I used the public key to verify a signed message an error pops out (error:0909006C:PEM routines:get_name:no) as result of EVP_VerifyFinal. Notice that, weird thing, the returning value of EVP_VerifyFinal is not 0 but -1: if it was 0 then It would be unrefutably a signature verification failure but it is not, it happens some other thing that I could not figure out. In the following I past the code used to sign and verify.
void sign(const unsigned char* const restrict clear_buf, const unsigned long clear_size, unsigned char* restrict* const restrict sgnt_buf, unsigned long* const restrict sgnt_size, const char* const restrict prvkey_file_name){
   const EVP_MD* md;
   EVP_MD_CTX* md_ctx;
   int ret;
   FILE* prvkey_file;
   EVP_PKEY* prvkey;
   unsigned expected_sgn_size;
   unsigned tmp;
   
   if(clear_size > INT_MAX){
       fprintf(stderr, "Buffer to sign too big\n");
       exit(1);
   }
   
   if((prvkey_file = fopen(prvkey_file_name, "r")) == NULL){
       fprintf(stderr, "Error: cannot open file '%s' (missing?)\n", prvkey_file_name);
       exit(1);
   }
   prvkey = PEM_read_PrivateKey(prvkey_file, NULL, NULL, NULL);
   fclose(prvkey_file);
   expected_sgn_size = (unsigned) EVP_PKEY_size(prvkey);
   if((*sgnt_buf = (unsigned char*)malloc((size_t)expected_sgn_size)) == NULL){
       fprintf(stderr, "Error in allocating memory for signature. Error: %s\n", strerror(errno));
       exit(1);
   }
   // create the signature context:
   md = EVP_sha256();
   md_ctx = EVP_MD_CTX_new();
   if(!md_ctx){
       fprintf(stderr, "Error: EVP_MD_CTX_new returned NULL\n");
       exit(1);
   }
   if(EVP_SignInit(md_ctx, md) == 0){
       fprintf(stderr, "Error: EVP_SignInit returned %d\n", ret);
       exit(1);
   }
   if(EVP_SignUpdate(md_ctx, clear_buf, (unsigned)clear_size) == 0){
       fprintf(stderr, "Error: EVP_SignUpdate returned %d\n", ret);
       exit(1);
   }
   if(EVP_SignFinal(md_ctx, *sgnt_buf, &tmp, prvkey) == 0){
       fprintf(stderr, "Error: EVP_SignFinal returned %d\n", ret);
       exit(1);
   }
   if(tmp < expected_sgn_size){
       fprintf(stderr, "Error in signing, signature size does not match expected size\n");
       exit(1);
   }
   
   *sgnt_size = (unsigned long)tmp;
   
   // delete the digest and the private key from memory:
   EVP_MD_CTX_free(md_ctx);
   EVP_PKEY_free(prvkey);
}
void verify(const unsigned char* const restrict file_buf, unsigned long* const restrict file_size, const char* const restrict pubkey_file_name){
   // declare some useful variables:
   int ret;
   FILE* pubkey_file;
   EVP_PKEY* pubkey;
   unsigned char* sgnt_buf;
   unsigned sgnt_size;
   
   pubkey_file = fopen(pubkey_file_name, "r");
   if(!pubkey_file){
       fprintf(stderr, "Error: cannot open file '%s' (missing?)\n", pubkey_file_name);
       exit(1);
   }
   pubkey = PEM_read_PUBKEY(pubkey_file, NULL, NULL, NULL);
   sgnt_size = (unsigned) EVP_PKEY_size(pubkey);
   fclose(pubkey_file);
   
   const EVP_MD* md = EVP_sha256();
   EVP_MD_CTX* md_ctx;
   
   *file_size -= (unsigned long)sgnt_size;
   if((sgnt_buf = (unsigned char*)malloc((size_t)sgnt_size)) == NULL){
       fprintf(stderr, "Error in allocating memory for signature. Error: %s\n", strerror(errno));
       exit(1);
   }
   memcpy((void*)sgnt_buf, (void*)(file_buf + *file_size), (size_t)sgnt_size);
   
   // create the signature context:
   md_ctx = EVP_MD_CTX_new();
   if(!md_ctx){
       fprintf(stderr, "Error: EVP_MD_CTX_new returned NULL\n");
       exit(1);
   }
   if(EVP_VerifyInit(md_ctx, md) == 0){
       fprintf(stderr, "Error in EVP_VerifyInit\n");
       exit(1);
   }
   if(EVP_VerifyUpdate(md_ctx, file_buf, *file_size) == 0){
       fprintf(stderr, "Error in EVP_VerifyUpdate\n");
       exit(1); 
   }
   ret = EVP_VerifyFinal(md_ctx, sgnt_buf, sgnt_size, pubkey);
   if(ret == 0){ // it is 0 if invalid signature, -1 if some other error, 1 if success.
       fprintf(stderr, "Error: EVP_VerifyFinal failed: invalid signature\n");
       exit(1);
   } else if(ret == -1){
       fprintf(stderr, "Some error occured during signature verification\n");
       exit(1);
   }else if (ret == 1){
       // fprintf(stdout, "Signature verified\n");
   }else{
       fprintf(stderr, "I shouldn't be printed. EVP_VerifyFinal returned %d\n", ret);
       exit(1);
   }
   EVP_MD_CTX_free(md_ctx);
   EVP_PKEY_free(pubkey);
   free(sgnt_buf);
}
On the web I found some solution but either they are not in C, or/and they are deprecated don't solve the problem (one solution that I found here generates a private key that it doesn't even sign for some reason...)
 
     
    