1 (edited by Scotty2541 2022-01-25 14:15:22)

Topic: Setting the valid date range when signing a cert

Hello,
Here is some background:
We are using our own internal CA.  And we need a device to generate and sign a certificate using the CA.

I have all this working fine. Modeling off of OpenSSL is how I started.
However OpenSSL uses a CNF file for those settings. No such option appears to exist.

I did find this:

https://wolfssl.com/doxygen/group__ASN. … 130e2c6563

WOLFSSL_API int wc_SetDatesBuffer    (Cert *, const byte * , int )
Which is one of the more useless explainations of how to function is used I've come across.

The example code is:

 Cert myCert;
 // initialize myCert
 byte* der;
 der = (byte*)malloc(FOURK_BUF);
 // initialize der
 if(wc_SetDatesBuffer(&myCert, der, FOURK_BUF) != 0) {
     // error setting subject
 }

Which only tells me I need a DER to use as a source for the dates...  Kind of a "circular" goal... 

Functionally, this all works, except the date is bad (dec 1969 as expected)
I need to be able to control the issue date and duration.

The (simplified) steps are:

    wc_MakeRsaKey()
    ...
    wc_InitCert(&testcert);
    strcpy(testcert.subject.country, "US");
    strcpy(testcert.subject.state, "IL");
    ... //  Yeah, a request is created, all fields good, and ready to be signed...

    caCertLength = LoadCACert();    //  Load the CA from storage
    wc_SetIssuerBuffer(testcert,m_caCert, caCertLength);
     ???  
    certsize = wc_MakeCert(&testcert, dercert, 4096, &genKey, NULL, &rng);
    caKeyLength = LoadCAKey();      //  Load the private key from storage
    result = wc_RsaPrivateKeyDecode((const byte *)m_caKey, &idx, &cakey, caKeyLength);
    ????
    certsize = wc_SignCert(testcert.bodySz, testcert.sigType, dercert, 4096, &cakey, NULL, &rng);

I am suspecting somewhere after "wc_SetIssueBuffer" or just before "wc_SignCert" is where the issue date and expiration date are set.
But there are no examples or explanations.

Can someone advise?

Thanks.

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Hi Scotty2541,

The function wc_SetDatesBuffer takes in a DER formatted certificate to use the date from it.

There is two main options for setting the date:

1) Set it directly in the Cert structure using the current API's you have listed. This is setting beforeDate, beforeDateSz, afterDate, afterDateSz, daysValid.

2) Use the compatibility layer APIs and create the certificate using WOLFSSL_X509 structure. This has the API's wolfSSL_X509_set_notBefore and wolfSSL_X509_set_notAfter. The function test_wolfSSL_X509_sign2 in tests/api.c has code testing the setting of a certificate date when creating it.

Regards,
Jacob

Share

Re: Setting the valid date range when signing a cert

Jacob,
Thanks.
BUT I also see fields for the size.  And my digging indicates that the OID for the fields are type 18 and defined as YYYYMMDDHHMMSSZ   (15 chars long)
Isn't this an implied and fixed size?

Also, what is the point of "daysValid" if we have a start and stop field already?   
What takes priority?  beforeDate + daysvalid?  Or afterDate to beforeDate  ?

typedef struct Cert {
    int      version;                   /* x509 version  */
    byte     serial[CTC_SERIAL_SIZE];   /* serial number */
    int      serialSz;                  /* serial size */
    int      sigType;                   /* signature algo type */
    CertName issuer;                    /* issuer info */
    int      daysValid;                 /* validity days */
    int      selfSigned;                /* self signed flag */
    CertName subject;                   /* subject info */
    int      isCA;                      /* is this going to be a CA */
    /* internal use only */
    int      bodySz;                    /* pre sign total size */
    int      keyType;                   /* public key type of subject */
#ifdef WOLFSSL_ALT_NAMES
    byte     altNames[CTC_MAX_ALT_SIZE]; /* altNames copy */
    int      altNamesSz;                 /* altNames size in bytes */
    byte     beforeDate[CTC_DATE_SIZE];  /* before date copy */
    int      beforeDateSz;               /* size of copy */
    byte     afterDate[CTC_DATE_SIZE];   /* after date copy */
    int      afterDateSz;                /* size of copy */
#endif

-------------------------------------------
As an aside, where do I find this documented?
1. This site: https://luca.ntop.org/Teaching/Appunti/asn1.html   shows a Generalize date as tag 17, but the cert uses 18

2. A DER Cert decoder I found shows everything,  http://lapo.it/asn1js/

But how does a cert KNOW which fields are what?  SOME of the entries have OID, and some don't.
There are OIDs that define the signature algorithm, but the DER sequence which contains two generalized time entries has no OID associated with it...  Does that just imply that two generalized time values are ALWAYS "NotValidBefore" and "NotValidAfter".

Is any of this actually defined somewhere?  Because every resource I've found just gives vague descriptions of ASN.1, BER, DER, etc...  Nothing that says "Here's a expected structure of a real cert needs to be".

-Scott
<Code shown is not to scale>

Share

4 (edited by Scotty2541 2022-01-26 10:11:34)

Re: Setting the valid date range when signing a cert

Jacob,
Simply added these lines to set the before and after date.  And now it makes a cert that fails...

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

    memcpy(testcert.beforeDate,"20220215060001Z",15);
    testcert.beforeDateSz = 15;
    memcpy(testcert.afterDate, "20240215060001Z",15);
    testcert.afterDateSz = 15;
    testcert.daysValid = 365*2;

    strcpy(testcert.subject.country, "US");
    strcpy(testcert.subject.state, "IL");

I stored of the PEM, and I get this:

openssl x509 -in Dated.pem -noout -text
WARNING: can't open config file: c:\source\lib\openssl-1.0.1g/ssl/openssl.cnf
unable to load certificate
18176:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:.\crypto\asn1\asn1_lib.c:142:
18176:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:.\crypto\asn1\tasn_dec.c:1306:
18176:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:210:Type=ASN1_TIME
18176:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:751:Field=notBefore, Type=X509_VAL
18176:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:751:Field=validity, Type=X509_CINF
18176:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:751:Field=cert_info, Type=X509
18176:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:.\crypto\pem\pem_oth.c:83:

So, what's the secret?

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Heres the setting broken down into the individual parts for you:


    newCert.beforeDate[0] = ASN_UTC_TIME;
    newCert.beforeDate[1] = ASN_UTC_TIME_SIZE - 1;
    newCert.beforeDate[2] = '2';   //year 2022
    newCert.beforeDate[3] = '2';   //year 2022
    newCert.beforeDate[4] = '0';   //month 02
    newCert.beforeDate[5] = '2';   //month 02
    newCert.beforeDate[6] = '1';   //day 15
    newCert.beforeDate[7] = '5';   //day 15
    newCert.beforeDate[8] = '0';   //hour 06
    newCert.beforeDate[9] = '6';   //hour 06
    newCert.beforeDate[10] = '0';  //minute 00
    newCert.beforeDate[11] = '0';  //minute 00
    newCert.beforeDate[12] = '0';  //second 01
    newCert.beforeDate[13] = '1';  //second 01
    newCert.beforeDate[14] = 'Z';
    newCert.beforeDateSz = 15;

    newCert.afterDate[0] = ASN_UTC_TIME;
    newCert.afterDate[1] = ASN_UTC_TIME_SIZE - 1;
    newCert.afterDate[2] = '2';   //year 2024
    newCert.afterDate[3] = '4';   //year 2024
    newCert.afterDate[4] = '0';   //month 02
    newCert.afterDate[5] = '2';   //month 02
    newCert.afterDate[6] = '1';   //day 15
    newCert.afterDate[7] = '5';   //day 15
    newCert.afterDate[8] = '0';   //hour 06
    newCert.afterDate[9] = '6';   //hour 06
    newCert.afterDate[10] = '0';  //minute 00
    newCert.afterDate[11] = '0';  //minute 00
    newCert.afterDate[12] = '0';  //second 01
    newCert.afterDate[13] = '1';  //second 01
    newCert.afterDate[14] = 'Z';
    newCert.afterDateSz = 15;

Having set the before and after you can remove the set of dayValid.

Regards,
Jacob

Share

Re: Setting the valid date range when signing a cert

Got it. Thanks.

Any experience running wc_MakeRsaKey() on a AM3352 chip?  It runs at about 1Gig.

It seems to be taking a long time to create a 2048 key pair.  What would be an expected time?  10 Seconds? 30 seconds? 60 seconds?

I know it's generating random numbers and trying some things.  So it will vary.

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

I don't see any benchmark values internally for the AM3352. We have a benchmark for a Rasperry PI at 1500 MHz with a 2048 bit RSA key generation. It took a little under a second at 700 ms. That was with --enable-fastmath and --enable-sp --enable-sp-asm.

Share

Re: Setting the valid date range when signing a cert

And how do I enable "--enable-fastmath" using a #define in the user_settings.h ?

Because we don't use the build scripts, as they are notoriously broken in CCS trying to build for platforms which are untested.

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Adding the macros;

#define USE_FAST_MATH
#define TFM_TIMING_RESISTANT
#define WC_RSA_BLINDING
#define ECC_TIMING_RESISTANT

and including wolfcrypt/src/tfm.c in the build should build it.

Regards,
Jacob

Share

Re: Setting the valid date range when signing a cert

USE_FAST_MATH was already defined.  And tfm.c is already being compiled in.

The others were not.  However it made no difference.
This is trying to create a new keypair.   
And it taking anywhere between 20 seconds and 75 seconds at a time, during the 15+ tests I've run.

Specifically this: 

result = wc_InitRng(&rng);

result = wc_InitRsaKey(&genKey,0);
result = wc_MakeRsaKey(&genKey, 2048, 65537, &rng);

Running in a task in TI RTOS.

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

In fact, here is the full list:

#ifndef WOLF_USER_SETTINGS_H_
#define WOLF_USER_SETTINGS_H_

#define USE_FAST_MATH
#define TFM_TIMING_RESISTANT
#define WC_RSA_BLINDING
#define ECC_TIMING_RESISTANT

#define ALT_ECC_SIZE

#define OPENSSL_EXTRA        /*   */

#define WOLFSSL_KEY_GEN        //  Needed to generate KEYS, CERTS, and alternate names
#define WOLFSSL_CERT_GEN
#define WOLFSSL_ALT_NAMES        //  Needed for altername subject names in cert generation

//  From the "settings.h"

    #define SIZEOF_LONG_LONG 8
    #define NO_ERROR_STRINGS
    #define FP_MAX_BITS 8192        /*  Increase for 4096 bit key */
    #define HAVE_ECC
    #define HAVE_ALPN
    #define USE_WOLF_STRTOK /* use with HAVE_ALPN */
    #define HAVE_TLS_EXTENSIONS
    #define HAVE_AESGCM

//  Speed up tests
#define WOLFSSL_SP_DH
#define WOLFSSL_HAVE_SP_ECC
#define WOLFSSL_SP_4096


//  New settings, trying to get client to connect
#define    WOLFSSL_AES_256

#define WOLFSSL_SHA384
#define WOLFSSL_SHA512

#define NO_PSK
#define HAVE_AESGCM
#define ECC_USER_CURVES
#define ECC_SHAMIR
#define WOLFSSL_RIPEMD
#define HAVE_EXTENDED_MASTER
#define WOLFSSL_CERT_EXT
-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Also, how is it that OpenSSL on a Windows i7 PC takes upwards of 15 seconds to create a new 2048 Public Private key pair  (and substantially longer for a 4096 pair), but you said this can do it in under a second on an Pi?

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Not sure, maybe OpenSSL key generation on Windows is just slow.....

Mac i7 with wolfSSL does around 6 generations per second for an average of 178.508 ms per generations. Without disabling any safe guards.

./wolfcrypt/benchmark/benchmark
...

RSA     2048 key gen         6 ops took 1.071 sec, avg 178.508 ms, 5.602 ops/sec
...

For the 20 seconds on the device there could be multiple factors 32bit vs 64bit for one, have ran into that previously or optimizations with the build flags. We would have to do some optimization investigations under a support contract for faster speeds.

Regards,
Jacob

Share

Re: Setting the valid date range when signing a cert

We have a support contract already in place.

-Scott
<Code shown is not to scale>

Share

Re: Setting the valid date range when signing a cert

Hi Scott,

Will forward the thread on to the support channel (support@wolfssl.com) using the 'user' email we have register to you on the forums here. That way we can be sure to handle it in a timely manner under the support contract and provide any optimization settings support specific to the use case.

Regards,
Jacob

Share

Re: Setting the valid date range when signing a cert

Jacob,
I got emails asking to create an account... is this new?

I've gotten support last year and the year before with our Digital Check account.  Dealing with you, Sean, Eric directly.

I'll try those other settings in a the next day or two.

Thanks.

-Scott
<Code shown is not to scale>

Share