Skip to content

Commit

Permalink
Added support for setting serial number (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsaarni authored Jun 19, 2022
1 parent e9381fd commit 793e193
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ Writing state: certs.state
| ca | Set certificate is / is not CA. If `ca` is not defined, `true` is set by default for self-signed certificates. | `true` or `false` |
| not_before | Certificate is not valid before this time ([RFC3339 timestamp](https://tools.ietf.org/html/rfc3339)) | `2020-01-01T09:00:00Z` |
| not_after | Certificate is not valid after this time ([RFC3339 timestamp](https://tools.ietf.org/html/rfc3339)) | `2020-01-01T09:00:00Z` |
| serial | Serial number for the certificate. Default value is current time in nanoseconds. | `123` |

## Go API

Expand Down
10 changes: 9 additions & 1 deletion certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ type Certificate struct {
// Default value is current time + Expires if NotAfter is undefined (when value is nil)
NotAfter *time.Time `json:"not_after"`

// SerialNumber defines serial number for the certificate.
// If not set, the default value is current time in nanoseconds.
SerialNumber *big.Int `json:"-" hash:"-"`

// GeneratedCert is a pointer to the generated certificate and private key.
// It is automatically set after calling any of the Certificate functions.
GeneratedCert *tls.Certificate `json:"-" hash:"-"`
Expand Down Expand Up @@ -230,6 +234,10 @@ func (c *Certificate) defaults() error {
}
}

if c.SerialNumber == nil {
c.SerialNumber = big.NewInt(time.Now().UnixNano())
}

return nil
}

Expand Down Expand Up @@ -305,7 +313,7 @@ func (c *Certificate) Generate() error {
name, _ := x500dn.ParseDN(c.Subject)

template := &x509.Certificate{
SerialNumber: big.NewInt(time.Now().UnixNano()),
SerialNumber: c.SerialNumber,
Subject: *name,
NotBefore: notBefore,
NotAfter: notAfter,
Expand Down
18 changes: 18 additions & 0 deletions certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"crypto/x509"
"encoding/pem"
"io/ioutil"
"math/big"
"net"
"net/url"
"os"
Expand Down Expand Up @@ -331,3 +332,20 @@ func TestRegenerate(t *testing.T) {
assert.NotEqual(t, old.Certificate, new.Certificate)
assert.NotEqual(t, old.PrivateKey, new.PrivateKey)
}

func TestSerial(t *testing.T) {
serial := big.NewInt(123)
input := Certificate{Subject: "CN=Joe", SerialNumber: serial}
got, err := input.X509Certificate()
assert.Nil(t, err)
assert.Equal(t, serial, got.SerialNumber)

// Check that unique serial is generated by default.
input1 := Certificate{Subject: "CN=Joe"}
input2 := Certificate{Subject: "CN=Joe"}
got1, err := input1.X509Certificate()
assert.Nil(t, err)
got2, err := input2.X509Certificate()
assert.Nil(t, err)
assert.NotEqual(t, got1.SerialNumber, got2.SerialNumber)
}
6 changes: 6 additions & 0 deletions internal/manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -56,6 +57,7 @@ type CertificateManifest struct {
ExpiresAsString string `json:"expires"`
IssuerAsString string `json:"issuer"`
Filename string `json:"filename"`
SerialNumberAsInt *int64 `json:"serial"`
}

func (c *CertificateManifest) hash() string {
Expand Down Expand Up @@ -205,6 +207,10 @@ func (m *Manifest) processCertificate(c *CertificateManifest) error {
c.ExtKeyUsage = usage
}

if c.SerialNumberAsInt != nil {
c.SerialNumber = big.NewInt(*c.SerialNumberAsInt)
}

// Try to load previously generated certificate and key, which might not exists, so ignore errors.
certOnDisk, err := tls.LoadX509KeyPair(path.Join(m.dataDir, c.Filename+".pem"), path.Join(m.dataDir, c.Filename+"-key.pem"))
if err == nil {
Expand Down
3 changes: 3 additions & 0 deletions internal/manifest/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"math/big"
"net"
"net/url"
"os"
Expand Down Expand Up @@ -234,4 +235,6 @@ func TestParsingAllCertificateFields(t *testing.T) {
assert.Empty(t, got.DNSNames)
assert.Empty(t, got.URIs)
assert.Empty(t, got.IPAddresses)

assert.Equal(t, big.NewInt(123), got.SerialNumber)
}
1 change: 1 addition & 0 deletions internal/manifest/testdata/certs-test-all-fields.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ subject: cn=ec-cert
key_size: 256
not_before: 2020-01-01T09:00:00Z
expires: 1h
serial: 123

0 comments on commit 793e193

Please sign in to comment.