What version of Go are you using (go version)?
go1.12.7 darwin/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
go env Output
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.12.7/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.12.7/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
What did you do?
I created an x509 certificate with x509.CreateCertificate from crypto/x509 with the following code (modified from Martian's mitm NewAuthority function):
package main
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"log"
"math/big"
"time"
)
var MaxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20))
func main() {
name := "Test name"
organization := "Test Org"
validity := time.Duration(24 * time.Hour)
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatal(err)
}
pub := priv.Public()
// Subject Key Identifier support for end entity certificate.
// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2)
pkixpub, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
log.Fatal(err)
}
h := sha1.New()
h.Write(pkixpub)
keyID := h.Sum(nil)
serial := MaxSerialNumber
tmpl := &x509.Certificate{
SerialNumber: serial,
Subject: pkix.Name{
CommonName: name,
Organization: []string{organization},
},
SubjectKeyId: keyID,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
NotBefore: time.Now().Add(-validity),
NotAfter: time.Now().Add(validity),
DNSNames: []string{name},
IsCA: true,
}
fmt.Println(MaxSerialNumber)
fmt.Println(serial)
raw, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, pub, priv)
fmt.Println(err, len(raw), raw)
}
(Unfortunately, this won't run in play.golang.org; it errors with process took too long.)
What did you expect to see?
A certificate with 20 bytes of serial number (which is the maximum allowed) where all 20 bytes are 255.
What did you see instead?
A certificate with 21 bytes of serial number, specifically, a 0 byte followed by 20 255 bytes. The field length correctly indicates 21 bytes, but some software will refuse to read a certificate with that many bytes.
The leading 0 byte is added whenever the big-end byte is >= 128. This can be seen by changing serial := MaxSerialNumber to serial := big.NewInt(127) and then serial := big.NewInt(128). The 127 serial number will have a field length of 1 byte, followed by the single byte 127. The 128 serial number will have a field length of 2 bytes, followed by the the two bytes 0 128.
What version of Go are you using (
go version)?Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env)?go envOutputWhat did you do?
I created an x509 certificate with
x509.CreateCertificatefromcrypto/x509with the following code (modified from Martian's mitm NewAuthority function):(Unfortunately, this won't run in play.golang.org; it errors with
process took too long.)What did you expect to see?
A certificate with 20 bytes of serial number (which is the maximum allowed) where all 20 bytes are
255.What did you see instead?
A certificate with 21 bytes of serial number, specifically, a
0byte followed by 20255bytes. The field length correctly indicates 21 bytes, but some software will refuse to read a certificate with that many bytes.The leading 0 byte is added whenever the big-end byte is >= 128. This can be seen by changing
serial := MaxSerialNumbertoserial := big.NewInt(127)and thenserial := big.NewInt(128). The 127 serial number will have a field length of 1 byte, followed by the single byte127. The 128 serial number will have a field length of 2 bytes, followed by the the two bytes0 128.