1 (edited by Scotty2541 2021-06-04 09:33:34)

Topic: Cannot sign a cert...

Hello,

See subject line.
I am trying to create and sign a certificate on the fly.  I've gone through the examples (some with bugs), dug through API doc, debugged over and over... and managed to piece together this sequence.

The code, and a dummy CA cert/key are attached.

The code below simply does (or is supposed to)

  • [1]Create a 2048 key pair
    [2]Convert it to DER
    [3]Then convert it to PEM
    [4]Save the private key.pem
    [5]Create a Cert
    [6]Load a CA
    [7]Set the issuer
    [8]Make the cert
    [9]Load the CA Key
    [10]Decode the CA key
    [11]Sign the Cert
    [12]Convert the Cert to PEM
    [13]Save the Cert.pem

It gives a corrupted PEM file.

I've gone as far as creating a self signed and it works.  Adding the steps to load the CA, set issuer, signed it are creating the bad PEM.  I can't remove any of those individual steps to see what is breaking.

This is a Windows based build as a first development concept.
Since this will ultimately be embedded without a file system, the code loads the ca/key and runs from memory buffers.

The last half of the PEM is simply uninitialized memory.

-----BEGIN CERTIFICATE-----
MIICeKADAgECAhAIA+FO9NCldJWF6ua77BzkMA0GCSqGSIb3DQEBBQUAMHsxCzAJ
BgNVBAYTAlhYMQswCQYDVQQIDAJYWDEQMA4GA1UEBwwHQW55Q2l0eTENMAsGA1UE
CgwERGVtbzENMAsGA1UECwwERGVtbzERMA8GA1UEAwwIZGVtby5jb20xHDAaBgkq
hkiG9w0BCQEWDWluZm9ARGVtby5jb20wIhgPMjAyMTA2MDMxMzAxMzVaGA8yMDIy
MTAxNzEzMDEzNVowgYgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJaWjESMBAGA1UE
BwwJVGhpcyBDaXR5MQ0wCwYDVQQKDARZYWRhMQwwCgYDVQQLDANEZXYxGTAXBgNV
BAMMEHd3dy53aGF0ZXZlci5jb20xIDAeBgkqhkiG9w0BCQEWEUluZm9Ad2hhdGV2
ZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Ilzmeb9p6h0
fB5uNXkxNbuFvPP3lXVoOqM9wpz+yD/I/tL7EmWjgGkrjC0EBFPp6GwGbeWMR8Ui
4nQNTSYuCSJXUv/W/q4pvyEcx4CM+Of5GxUNRnDrQeVbHoiWfum2TGqPngzJVGiO
7ji6j3xlGUqQowS3CNQVAmKcXdVXaWJWyFfzbl5AjBlRjUgX08YsXc1bP7Wg291Z
88U7aY2skIgv1TJiftZrlxvPHa+uRMql5OS6cQkQ2psXRvEHurvwkij4MMUJaoCs
0uRmX8qDy1tXX/GwN6kGFcuoPJwNH7tP3adTFFrmWeevLL5n1xZmWovor15CxpXC
BsxPwKdclwIDAQABzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM
zMzMzMzMzMzMzMzMzMzMzMzMzMw=
-----END CERTIFICATE-----

This is the code being used.  ALL the return codes are good (even though they are not tested, they are good as I step through with the debugger)

#include <stdio.h>

#include "wolfssl\ssl.h"
#include "wolfssl/wolfcrypt\asn_public.h"    /*  Used for cert generation */
#include "wolfssl/wolfcrypt/rsa.h"        /*  Used for RNG and RSA Key */


int main() {
    RsaKey genKey;
    int result;
    RNG rng;
    FILE *fp;
    wc_InitRng(&rng);

    wc_InitRsaKey(&genKey,0);

    wc_MakeRsaKey(&genKey, 2048, 65537, &rng);
    /*  Save off the private key we are going to use  */
    byte keyDer[4096];
    int keysize, keypemsize;
    keysize = wc_RsaKeyToDer(&genKey, keyDer, 4096);

    byte keypem[4096];
    keypemsize = wc_DerToPem(keyDer, keysize, keypem, 4096, PRIVATEKEY_TYPE);

    /*  Save the new private key */
    fp = fopen("TestprivateKey.pem", "w+");
    fwrite(keypem, 1, keypemsize, fp);
    fclose(fp);

    /*  Create a CERT */
    Cert testcert;
    wc_InitCert(&testcert);

    strcpy(testcert.subject.country, "US");
    strcpy(testcert.subject.state, "ZZ");
    strcpy(testcert.subject.locality, "This City");
    strcpy(testcert.subject.org, "Yada");
    strcpy(testcert.subject.unit, "Dev");
    strcpy(testcert.subject.commonName, "www.whatever.com");
    strcpy(testcert.subject.email, "Info@whatever.com");
    byte dercert[4096];
    int certsize, certpemsize;
    /*  Use for SELF SIGNED */
    //certsize = wc_MakeSelfCert(&testcert, dercert, 4096, &genKey, &rng);

    /*  Use to sign it */
    /*  Load the CA cert to use */
    int cacertbufsize;
    unsigned char cacertbuf[4096];
    byte cacertder[4096];
    fp = fopen("sampleCA.pem", "r");
    cacertbufsize = fread(cacertbuf, 1, 4096, fp);
    fclose(fp);
        /*  Need to convert it to DER  */
    cacertbufsize = wc_CertPemToDer(cacertbuf, cacertbufsize, cacertder, 4096, CERT_TYPE);
    result = wc_SetIssuerBuffer(&testcert, cacertder, cacertbufsize);

    /*  Now we can make the certificate */
    certsize = wc_MakeCert(&testcert, dercert, 4096, &genKey, NULL, &rng);

    /*  Now load the CA key  */
    RsaKey cakey;
    int cakeybufsize;
    unsigned char cakeybuf[4096];
    word32 idx = 0;
    fp = fopen("sampleCAkey.pem", "r");
    cakeybufsize = fread(cakeybuf, 1, 4096, fp);
    fclose(fp);
    unsigned char caderkey[4096];
    /*  Need to conver it to DER  */
    wc_InitRsaKey(&cakey, 0);
    cakeybufsize = wc_KeyPemToDer(cakeybuf, cakeybufsize, caderkey, 4096, "ByteMe");
    result = wc_RsaPrivateKeyDecode((const byte *)caderkey, &idx,&cakey, cakeybufsize);

    /*  Now we sign the certificate  */
    byte signedcert[4096];
    certsize = wc_SignCert(testcert.bodySz, testcert.sigType, signedcert, 4096, &cakey, NULL, &rng);

    /* Convert the DER to PEM  */
    byte pemcert[4096];
    certpemsize = wc_DerToPem(dercert, certsize, pemcert, 4096, CERT_TYPE);

    /*  Save the signed signed cert  */
    fp = fopen("TestprivateCert.pem", "w+");
    fwrite(pemcert, 1, certpemsize, fp);
    fclose(fp);
    return 0;
}
Post's attachments

CertGen.zip 5.21 kb, file has never been downloaded. 

You don't have the permssions to download the attachments of this post.
-Scott
<Code shown is not to scale>

Share

Re: Cannot sign a cert...

Hi Scott,

Have you see our wolfssl-examples repo? Specifically these examples for CSR generation and signing?
https://github.com/wolfSSL/wolfssl-exam … er/certgen

We also have a good one in wolfTPM here:
https://github.com/wolfSSL/wolfTPM/blob … /csr/csr.c

I also saw your note about Doxygen quality and will bring up with the team.

Thanks,
David Garske, wolfSSL

Share

Re: Cannot sign a cert...

Found it...
It doesn't generate a new buffer from the existing cert.  You feed it the existing cert.

    //  Now we can make the certificate 
    certsize = wc_MakeCert(&testcert, dercert, 4096, &genKey, NULL, &rng);
...
...
    //  Now we sign the certificate  
    //   byte signedcert[4096];
    //    certsize = wc_SignCert(testcert.bodySz, testcert.sigType, signedcert, 4096, &cakey, NULL, &rng);
    certsize = wc_SignCert(testcert.bodySz, testcert.sigType, dercert, 4096, &cakey, NULL, &rng);

And yet, you have to feed it the Cert object fields (testcert in this example), but the DER structured certificate.  But they both represent the same thing.

By the way... regarding doxygen, you know that wc_KeyPemToDer isn't anywhere to be found?

-Scott
<Code shown is not to scale>

Share

Re: Cannot sign a cert...

Hi Scott,

I will load up your test and see if I can spot the issue. I do have some other cert gen/sign examples that are not public.

Note: The API `wc_KeyPemToDer` used to be named `wolfSSL_KeyPemToDer`, which you will find docs for.

Thanks,
David Garske, wolfSSL

Share

Re: Cannot sign a cert...

Hi Scott,

I found a couple bugs in your code:
1) The wc_SignCert needs to pass the existing dercert that was used on wc_MakeCert.
2) The output size from wc_SignCert was not being captured and used.

Here is the fully working example, which can be used from the wolfSSL root:

#include <stdio.h>

#include "wolfssl/options.h"
#include "wolfssl/wolfcrypt/settings.h"
#include "wolfssl/wolfcrypt/asn_public.h"    /*  Used for cert generation */
#include "wolfssl/wolfcrypt/random.h"
#include "wolfssl/wolfcrypt/rsa.h"        /*  Used for RNG and RSA Key */

/*
./configure CFLAGS="-DKEEP_PEER_CERT -DWOLFSSL_ALT_NAMES" --enable-keygen --enable-certgen --enable-sni --enable-debug && make
sudo make install
gcc -Wall -g -o certgen_sign -lwolfssl certgen_sign.c 
 */

#define MAX_BUF_SZ 4096

int main() {
    int res;
    word32 idx = 0;
    RsaKey genKey;
    RsaKey cakey;
    WC_RNG rng;
    FILE *fp;

    int cacertbufsize;
    byte cacertbuf[MAX_BUF_SZ*2];

    byte cacertder[MAX_BUF_SZ];    

    int cakeybufsize;
    byte cakeybuf[MAX_BUF_SZ];
    
    byte pemcert[MAX_BUF_SZ];

    byte dercert[MAX_BUF_SZ];
    int certsize;
    int certpemsize;
    
    byte caderkey[MAX_BUF_SZ];

    int keysize;
    byte keyDer[MAX_BUF_SZ];

    int keypemsize;
    byte keypem[MAX_BUF_SZ];

    Cert testcert;

    memset(&rng, 0, sizeof(rng));
    memset(&cakey, 0, sizeof(cakey));
    memset(&genKey, 0, sizeof(genKey));
    memset(&testcert, 0, sizeof(testcert));

    res = wc_InitRng(&rng);
    if (res != 0) goto exit;

    res = wc_InitRsaKey(&genKey,0);
    if (res != 0) goto exit;

    res = wc_MakeRsaKey(&genKey, 2048, 65537, &rng);
    if (res != 0) goto exit;

    /*  Save off the private key we are going to use  */
    res = wc_RsaKeyToDer(&genKey, keyDer, sizeof(keyDer));
    if (res < 0) goto exit;
    keysize = res;

    res = wc_DerToPem(keyDer, keysize, keypem, sizeof(keypem), PRIVATEKEY_TYPE);
    if (res < 0) goto exit;
    keypemsize = res;

    /*  Save the new private key */
    fp = fopen("TestprivateKey.pem", "w+");
    if (fp == NULL) { res = -1; goto exit; }
    fwrite(keypem, 1, keypemsize, fp);
    fclose(fp);

    /*  Create a CERT */
    wc_InitCert(&testcert);
    testcert.sigType = CTC_SHA256wRSA;
    testcert.isCA = 0;
    strcpy(testcert.subject.country, "US");
    strcpy(testcert.subject.state, "ZZ");
    strcpy(testcert.subject.locality, "This City");
    strcpy(testcert.subject.org, "Yada");
    strcpy(testcert.subject.unit, "Dev");
    strcpy(testcert.subject.commonName, "www.whatever.com");
    strcpy(testcert.subject.email, "Info@whatever.com");
    
    /*  Use for SELF SIGNED */
    //certsize = wc_MakeSelfCert(&testcert, dercert, sizeof(dercert), &genKey, &rng);

    /*  Use to sign it */
    /*  Load the CA cert to use */
    fp = fopen("./certs/ca-cert.pem", "r");
    if (fp == NULL) { res = -1; goto exit; }
    cacertbufsize = fread(cacertbuf, 1, sizeof(cacertbuf), fp);
    fclose(fp);

    /*  Need to convert it to DER  */
    res = wc_CertPemToDer(cacertbuf, cacertbufsize, cacertder, sizeof(cacertder), CERT_TYPE);
    if (res < 0) goto exit;
    cacertbufsize = res;
    res = wc_SetIssuerBuffer(&testcert, cacertder, cacertbufsize);
    if (res != 0) goto exit;

    /*  Now we can make the certificate */
    res = wc_MakeCert_ex(&testcert, dercert, sizeof(dercert), RSA_TYPE, &genKey, &rng);
    if (res < 0) goto exit;
    certsize = res;

    /*  Now load the CA key  */
    fp = fopen("./certs/ca-key.pem", "r");
    if (fp == NULL) { res = -1; goto exit; }
    cakeybufsize = fread(cakeybuf, 1, sizeof(cakeybuf), fp);
    fclose(fp);
    
    /*  Need to conver it to DER  */
    wc_InitRsaKey(&cakey, 0);
    res = wc_KeyPemToDer(cakeybuf, cakeybufsize, caderkey, sizeof(caderkey), NULL /* no password */);
    if (res < 0) goto exit;
    cakeybufsize = res;

    res = wc_RsaPrivateKeyDecode((const byte *)caderkey, &idx, &cakey, cakeybufsize);
    if (res < 0) goto exit;

    /*  Now we sign the certificate  */
    res = wc_SignCert(testcert.bodySz, testcert.sigType, dercert, sizeof(dercert), &cakey, NULL, &rng);
    if (res < 0) goto exit;
    certsize = res;

    /*  Save the signed signed cert (DER) */
    fp = fopen("TestprivateCert.der", "w+");
    if (fp == NULL) { res = -1; goto exit; }
    fwrite(dercert, 1, certsize, fp);
    fclose(fp);

    /* Convert the DER to PEM */
    res = wc_DerToPem(dercert, certsize, pemcert, sizeof(pemcert), CERT_TYPE);
    if (res < 0) goto exit;
    certpemsize = res;
    res = 0; /* success */

    /*  Save the signed signed cert (PEM) */
    fp = fopen("TestprivateCert.pem", "w+");
    if (fp == NULL) { res = -1; goto exit; }
    fwrite(pemcert, 1, certpemsize, fp);
    fclose(fp);

exit:

    printf("Result %d\n", res);

    wc_FreeRsaKey(&cakey);
    wc_FreeRsaKey(&genKey);
    wc_FreeRng(&rng);
    return res;
}

Thanks,
David Garske, wolfSSL

Share