Search code examples
opensslx509certificatex509

regarding openssl upgrade of i2d_X509_REQ() api from version 1.1.1 to 3.0.5


I have upgraded from openssl 1.1.1 to opessl 3.0.5. I am getting error in the i2d_X509_REQ(X509_REQ* req, nullptr) api to get the length of the content in openssl 3.0.5. I am getting the error of length of -1. Can anyone guide me fix this compatability issue? Many thanks in advance. Also, is it possible to print the reason for error due to openssl api's? It will be used to find the exact error occurred.

#include <iostream>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/engine.h>
#include <filesystem>
#include <openssl/x509.h>
using namespace std;


int main()
{
    EVP_PKEY_CTX *ctx;
    EVP_PKEY *pkey = NULL;
    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    if (!ctx) {
        std::cout<<"ctx error"<<std::endl;
    }
        /* Error occurred */
    if (EVP_PKEY_keygen_init(ctx) <= 0) {
        std::cout<<"EVP_PKEY_CTX_new_id error"<<std::endl;
    }

    if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 4096) <= 0) {
        std::cout<<"EVP_PKEY_CTX_set_rsa_keygen_bits error"<<std::endl;
    }

    /* Generate key */
    if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
        std::cout<<"EVP_PKEY_keygen error"<<std::endl;
    }

    /* Writes the generated key to file*/
    FILE *fp;
    fp = fopen("/home/tpb1cob/1day/openssl/public_key.txt","w");
    if (0 == PEM_write_PUBKEY(fp,pkey)) {
        std::cout<<"file write fail"<<std::endl;
    }
    fclose(fp);

    /*Encode the key and write to buffer*/
    unsigned char* p;
    int ret = -1;
    ret = i2d_PublicKey(pkey,&p);
    if(ret < 0) {
        std::cout<<"i2d_PublicKey returns negative value"<<ret<<std::endl;
    }
    std::cout<<"i2d_PublicKey returns value "<<ret<<std::endl;
    std::cout<<p<<std::endl;

    /*Decodes buffer contents and assign to EVP_Key structure*/
    EVP_PKEY *pkey1 = NULL;
    if(NULL == d2i_PublicKey(EVP_PKEY_RSA,&pkey1,(const unsigned char**)&p,526)) {
        std::cout<<"d2i_PrivateKey_fp returns NULL pointer"<<std::endl;
    }

    /* Writes the decoded key to file*/
    FILE *fpq;
    fpq = fopen("/home/tpb1cob/1day/openssl/public_key_decoded.txt","w");
    if (0 == PEM_write_PUBKEY(fpq,pkey1)) {
        std::cout<<"file write fail"<<std::endl;
    }
    fclose(fpq);
    
    /* checks the parameters of keys pkey and pkey1 for equality */
    if(1 == EVP_PKEY_eq(pkey,pkey1)) {
        std::cout<<"EVP_PKEY_eq success"<<std::endl;
    }
    

    //"C=UK, O=Disorganized Organization, CN=Joe Bloggs"

    X509_NAME *nm;
    X509_REQ *CR;

    nm = X509_NAME_new();
    CR = X509_REQ_new();    
    if (nm == NULL) {
        std::cout<<"X509_NAME_new failed"<<std::endl;
    }
        /* Some error */

    int ii = -1;

     if (1 == X509_NAME_add_entry_by_txt(nm, "C", MBSTRING_ASC,(const unsigned char*)"UK", -1, -1, 0)) {
        std::cout<<"X509_NAME_add_entry_by_txt country success"<<std::endl;
    }
        /* Error */
    if (1 == X509_NAME_add_entry_by_txt(nm, "O", MBSTRING_ASC,(const unsigned char*)"Disorganized Organization", -1, -1, 0)) {
        std::cout<<"X509_NAME_add_entry_by_txt organization success"<<std::endl;
    }
    
    if (1 == X509_NAME_add_entry_by_txt(nm, "OU", MBSTRING_ASC,(const unsigned char*)"Organization Unit", -1, -1, 0)) {
        std::cout<<"X509_NAME_add_entry_by_txt organization unit success"<<std::endl;
    }
        /* Error */
    if (1 == X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC,(const unsigned char*)"Joe Bloggs", -1, -1, 0)) {
        std::cout<<"X509_NAME_add_entry_by_txt common name success"<<std::endl;
    }

    if (1 == X509_REQ_set_subject_name(CR, nm)) {
        std::cout<<"X509_REQ_set_subject_name success"<<std::endl;
    }
    
    X509_NAME_free(nm);

    if(1 == X509_REQ_set_pubkey(CR, pkey)) {
        std::cout<<"X509_REQ_set_pubkey success"<<std::endl;
    }

    int length = i2d_X509_REQ(CR, NULL);
    const char** file;
    int* line;

    if (length <= 0) {
        std::cout<<"i2d_X509_REQ fail"<<length<<std::endl;
    }
    
    return 0;
}

I tried to get the length of certificate request but its always returning -1.


Solution

  • Reversing your questions:

    Also, is it possible to print the reason for error due to openssl api's?

    Yes. See the FAQ and the man page. In some cases you may need your code to look in more detail using the more basic methods but I wouldn't start there. (Be warned however that the next FAQ, PROG9, is obsolete; in OpenSSL 1.1.0 up the error strings are always loaded automatically and you no longer need to code for them. Also while all failures from libcrypto routines should give error-queue information, libssl is different; routines like SSL_connect and SSL_read in nonblocking mode, or at EOF, can 'fail' without any error and you should call SSL_get_error to resolve those before looking at ERR_*.)

    Can anyone guide me fix this compatability issue?

    Doing ERR_print_errors_fp after the failed call to i2d_X509_REQ in your code gives

    {thread}:error:068000DE:asn1 encoding routines:(unknown function):illegal zero content:crypto/asn1/tasn_enc.c:374:
    

    which, although not totally obvious, is because you didn't sign the request and thus the values for the signatureAlgorithm and signature, which are required parts of the actual PKCS10 structure, are missing.

    Solution: call X509_REQ_sign[_ctx] (using your generated EVP_PKEY which contains both the privatekey and publickey) first.

    Also note that you are writing out the public half of your keypair (with PEM_write_PUBKEY) but not the private half. If you don't save the privatekey somewhere, your CSR is basically useless, because any certificate obtained from that CSR can only be used sucessfully in conjunction with the privatekey.

    Finally, your 'encode then decode publickey' code is unsafe; it declares unsigned char * p and then uses it without initialization. Probably the compiler you use on the system you use happened to create it in such a way it contained 0/null which (more or less) works, but you shouldn't depend on this.