Programmatically generate a CA Certificate with openssl in C++

Viewed 2136

I want to generate a CA Certificate with openssl and C++, to then use it to sign certificates. So I implemented a function to generate Certificates:

std::shared_ptr<X509> SSL_Utilities::generateCertificate(std::shared_ptr<EVP_PKEY> pkey, std::map<std::string, std::string> subject_fields, std::map<std::string, std::string> issuer_fields)
{
    if(!pkey)return nullptr;

    X509 *x509 = X509_new();
    X509_set_version(x509, 2);

    auto p_serial_number = ASN1_INTEGER_new();
    randSerial(p_serial_number);
    X509_set_serialNumber(x509, p_serial_number);

    X509_gmtime_adj(X509_get_notBefore(x509), 0);
    X509_gmtime_adj(X509_get_notAfter(x509), (long)60*60*24*365);
    X509_set_pubkey(x509, pkey.get());

    X509_NAME *name = X509_get_subject_name(x509);
    for(auto f : subject_fields){
        X509_NAME_add_entry_by_txt(name, f.first.c_str(), MBSTRING_ASC, (const unsigned char*)f.second.c_str(), -1, -1, 0);
    }
    X509_set_subject_name(x509,name);

    name = X509_get_issuer_name(x509);
    for(auto f : issuer_fields){
        X509_NAME_add_entry_by_txt(name, f.first.c_str(), MBSTRING_ASC, (const unsigned char*)f.second.c_str(), -1, -1, 0);
    }
    X509_set_issuer_name(x509,name);

    X509_sign(x509, pkey.get(), EVP_sha512());

    return std::shared_ptr<X509>(x509,X509_free);
}

This code was then used to generate a CA certificate. Afterwards I generated sign requests for a server and a client, signed them with the generated CA Certificate and Key and tried to connect the Server and Client, which did not work.

So I tried generating a CA with openssl command-line, loaded it into my program, created Sign requests, signed them and the Server and Client could connect. This means that the problem lies inside the CA Certificate. When comparing the certificate generated in C with the one generated on the command line I detected that the one generated in C missed the following stuff:

X509v3 extensions:
            X509v3 Subject Key Identifier: 
                93:72:AB:40:A4:E8:6F:D3:26:F2:F8:54:6F:A0:94:97:79:99:65:E6
            X509v3 Authority Key Identifier: 
                keyid:93:72:AB:40:A4:E8:6F:D3:26:F2:F8:54:6F:A0:94:97:79:99:65:E6

            X509v3 Basic Constraints: critical
                CA:TRUE

I tried adding the Basic Constraints field with the following code:

    ASN1_STRING * str = ASN1_OCTET_STRING_new();
    const char * ee = "CA:TRUE";
    ASN1_STRING_set(str,(const void*)ee,strlen(ee));

    X509_EXTENSION * ext = nullptr;
    X509_EXTENSION_create_by_NID(&ext,NID_basic_constraints,1,str);

    X509_add_ext(x509,ext,-1);

and the generated certificate looks like the Field was added, but when I try to use it I get the following Error in the Client-Code (After SSL_Connect):

140120891770752:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:../crypto/asn1/asn1_lib.c:91:
140120891770752:error:0D068066:asn1 encoding routines:asn1_check_tlen:bad object header:../crypto/asn1/tasn_dec.c:1118:
140120891770752:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:290:Type=BASIC_CONSTRAINTS
140120891770752:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1919:

Any idea what I am doing wrong? Thanks.

1 Answers

Looking that this example it seems to do what you want to do:

int add_ext(X509 *cert, int nid, char *value)
    {
    X509_EXTENSION *ex;
    X509V3_CTX ctx;
    /* This sets the 'context' of the extensions. */
    /* No configuration database */
    X509V3_set_ctx_nodb(&ctx);
    /* Issuer and subject certs: both the target since it is self signed,
     * no request and no CRL
     */
    X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
    if (!ex)
        return 0;

    X509_add_ext(cert,ex,-1);
    X509_EXTENSION_free(ex);
    return 1;
    }


    /* Add various extensions: standard extensions */
    add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
    add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");

    add_ext(x, NID_subject_key_identifier, "hash");
Related