From b3f10b9a4cfeb8c384282f3e61aaf7356efab636 Mon Sep 17 00:00:00 2001 From: Emman Date: Fri, 15 Apr 2022 11:01:11 +0800 Subject: [PATCH] #43, crypto/x509: don't allow too long serials --- smx509/x509.go | 12 ++++++++++++ smx509/x509_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/smx509/x509.go b/smx509/x509.go index 62ff1a4..6ae11fc 100644 --- a/smx509/x509.go +++ b/smx509/x509.go @@ -1284,6 +1284,18 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, return nil, errors.New("x509: no SerialNumber given") } + // RFC 5280 Section 4.1.2.2: serial number must not be longer than 20 octets + // + // We cannot simply check for len(serialBytes) > 20, because encoding/asn1 may + // pad the slice in order to prevent the integer being mistaken for a negative + // number (DER uses the high bit of the left-most byte to indicate the sign.), + // so we need to double check the composition of the serial if it is exactly + // 20 bytes. + serialBytes := template.SerialNumber.Bytes() + if len(serialBytes) > 20 || (len(serialBytes) == 20 && serialBytes[0]&0x80 != 0) { + return nil, errors.New("x509: serial number exceeds 20 octets") + } + if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) { return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") } diff --git a/smx509/x509_test.go b/smx509/x509_test.go index 88a719a..7f0defa 100644 --- a/smx509/x509_test.go +++ b/smx509/x509_test.go @@ -2429,3 +2429,39 @@ func TestDisableSHA1ForCertOnly(t *testing.T) { t.Errorf("unexpected error: %s", err) } } + +func TestCreateCertificateLongSerial(t *testing.T) { + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + + serialBytes := make([]byte, 21) + serialBytes[0] = 0x80 + serialBytes[20] = 1 + tooLong := big.NewInt(0).SetBytes(serialBytes) + + tmpl := &Certificate{ + SerialNumber: tooLong, + Subject: pkix.Name{ + CommonName: ":)", + }, + NotAfter: time.Now().Add(time.Hour), + NotBefore: time.Now().Add(-time.Hour), + } + + expectedErr := "x509: serial number exceeds 20 octets" + + _, err = CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), k.Public(), k) + if err == nil || err.Error() != expectedErr { + t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err) + } + + serialBytes = serialBytes[:20] + tmpl.SerialNumber = big.NewInt(0).SetBytes(serialBytes) + + _, err = CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), k.Public(), k) + if err == nil || err.Error() != expectedErr { + t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err) + } +}