From 6548f32ee08d79836d41171ad3311855713b6654 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 11 Oct 2017 17:21:26 -0700 Subject: [PATCH] Enhancement to allow a serial number to be customized via `Cert.serial` and `Cert.serialSz` for cert request or generation. Fix to make sure serial number is always postive and has no leading zeros. Increase the size of the certificate serial number to 20 bytes. --- wolfcrypt/src/asn.c | 83 +++++++++++++++++----------------- wolfssl/wolfcrypt/asn_public.h | 3 +- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 24521897e..9b31f9cb2 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6370,31 +6370,30 @@ WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header) WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output) { - int result = 0; - - WOLFSSL_ENTER("SetSerialNumber"); + int i = 0; + int snSzInt = (int)snSz; if (sn == NULL || output == NULL) return BAD_FUNC_ARG; - if (snSz <= EXTERNAL_SERIAL_SIZE) { - output[0] = ASN_INTEGER; - /* The serial number is always positive. When encoding the - * INTEGER, if the MSB is 1, add a padding zero to keep the - * number positive. */ - if (sn[0] & 0x80) { - output[1] = (byte)snSz + 1; - output[2] = 0; - XMEMCPY(&output[3], sn, snSz); - result = snSz + 3; - } - else { - output[1] = (byte)snSz; - XMEMCPY(&output[2], sn, snSz); - result = snSz + 2; - } + /* remove leading zeros */ + while (snSzInt > 0 && sn[0] == 0) { + snSzInt--; + sn++; } - return result; + + /* encode ASN Integer, with length and value */ + output[i++] = ASN_INTEGER; + i += SetLength(snSzInt, &output[i]); + XMEMCPY(&output[i], sn, snSzInt); + + /* ensure positive (MSB not set) */ + output[i] &= ~0x80; + + /* compute final length */ + i += snSzInt; + + return i; } WOLFSSL_LOCAL int GetSerialNumber(const byte* input, word32* inOutIdx, @@ -6953,6 +6952,7 @@ int wc_InitCert(Cert* cert) #endif cert->keyType = RSA_KEY; XMEMSET(cert->serial, 0, CTC_SERIAL_SIZE); + cert->serialSz = 0; cert->issuer.country[0] = '\0'; cert->issuer.countryEnc = CTC_PRINTABLE; @@ -7063,18 +7063,6 @@ static word32 SetUTF8String(word32 len, byte* output) #endif /* WOLFSSL_CERT_REQ */ -/* Write a serial number to output */ -static int SetSerial(const byte* serial, byte* output) -{ - int length = 0; - - output[length++] = ASN_INTEGER; - length += SetLength(CTC_SERIAL_SIZE, &output[length]); - XMEMCPY(&output[length], serial, CTC_SERIAL_SIZE); - - return length + CTC_SERIAL_SIZE; -} - #endif /* defined(WOLFSSL_CERT_GEN) && !defined(NO_RSA) */ #if defined(HAVE_ECC) && (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)) @@ -8169,13 +8157,20 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, /* version */ der->versionSz = SetMyVersion(cert->version, der->version, TRUE); - /* serial number */ - ret = wc_RNG_GenerateBlock(rng, cert->serial, CTC_SERIAL_SIZE); - if (ret != 0) - return ret; - - cert->serial[0] = 0x01; /* ensure positive */ - der->serialSz = SetSerial(cert->serial, der->serial); + /* serial number (must be positive) */ + if (cert->serialSz == 0) { + /* generate random serial */ + cert->serialSz = CTC_SERIAL_SIZE; + ret = wc_RNG_GenerateBlock(rng, cert->serial, cert->serialSz); + if (ret != 0) + return ret; + } + else if (cert->serialSz > CTC_SERIAL_SIZE) { + cert->serialSz = CTC_SERIAL_SIZE; + } + der->serialSz = SetSerialNumber(cert->serial, cert->serialSz, der->serial); + if (der->serialSz < 0) + return der->serialSz; /* signature algo */ der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, oidSigType, 0); @@ -11067,8 +11062,8 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size) byte issuerKeyArray[MAX_ENCODED_DIG_SZ]; byte snArray[MAX_SN_SZ]; byte extArray[MAX_OCSP_EXT_SZ]; - word32 seqSz[5], algoSz, issuerSz, issuerKeySz, snSz, extSz, totalSz; - int i; + word32 seqSz[5], algoSz, issuerSz, issuerKeySz, extSz, totalSz; + int i, snSz; WOLFSSL_ENTER("EncodeOcspRequest"); @@ -11078,11 +11073,17 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size) algoSz = SetAlgoID(SHAh, algoArray, oidHashType, 0); #endif + if (req->serialSz > EXTERNAL_SERIAL_SIZE) + req->serialSz = EXTERNAL_SERIAL_SIZE; + issuerSz = SetDigest(req->issuerHash, KEYID_SIZE, issuerArray); issuerKeySz = SetDigest(req->issuerKeyHash, KEYID_SIZE, issuerKeyArray); snSz = SetSerialNumber(req->serial, req->serialSz, snArray); extSz = 0; + if (snSz < 0) + return snSz; + if (req->nonceSz) { /* TLS Extensions use this function too - put extensions after * ASN.1: Context Specific [2]. diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index d9addfe97..77feeee2b 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -99,7 +99,7 @@ enum Ctc_Misc { CTC_NAME_SIZE = 64, CTC_DATE_SIZE = 32, CTC_MAX_ALT_SIZE = 16384, /* may be huge */ - CTC_SERIAL_SIZE = 8, + CTC_SERIAL_SIZE = 20, #ifdef WOLFSSL_CERT_EXT /* AKID could contains: hash + (Option) AuthCertIssuer,AuthCertSerialNum * We support only hash */ @@ -136,6 +136,7 @@ typedef struct CertName { 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 */