From d7194932dcd1fbb7e55c16d9fd954d1da65ba3db Mon Sep 17 00:00:00 2001 From: "Andrew E. Bruno" Date: Tue, 19 Nov 2019 11:10:16 -0500 Subject: [PATCH 1/2] Add option for creating code-signing certificates. This commit adds support for signing certificates with the codeSigning extended key usage extension. Tried to make this as non-invasive as possible by adding a new function to create host certificates api with an optional array of []x509.ExtKeyUsage. This should allow adding support for other extended key usages in the future. For now, just added a simple boolean flag to the sign command with turns this on. --- cmd/sign.go | 11 +++++++++++ pkix/cert_host.go | 10 ++++++++++ pkix/cert_host_test.go | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/cmd/sign.go b/cmd/sign.go index bb9c317..0e826a1 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -18,6 +18,7 @@ package cmd import ( + "crypto/x509" "fmt" "os" "strings" @@ -67,6 +68,10 @@ func NewSignCommand() cli.Command { Name: "intermediate", Usage: "Whether generated certificate should be a intermediate", }, + cli.BoolFlag{ + Name: "codsigning", + Usage: "Whether generated certificate should include the codeSigning extended key usage extension", + }, }, Action: newSignAction, } @@ -141,6 +146,12 @@ func newSignAction(c *cli.Context) { if c.Bool("intermediate") { fmt.Fprintln(os.Stderr, "Building intermediate") crtOut, err = pkix.CreateIntermediateCertificateAuthority(crt, key, csr, expiresTime) + } else if c.Bool("codesigning") { + fmt.Fprintln(os.Stderr, "Including codeSigning extended key usage") + extKeyUsage := []x509.ExtKeyUsage{ + x509.ExtKeyUsageCodeSigning, + } + crtOut, err = pkix.CreateCertificateHostWithExtUsage(crt, key, csr, expiresTime, extKeyUsage) } else { crtOut, err = pkix.CreateCertificateHost(crt, key, csr, expiresTime) } diff --git a/pkix/cert_host.go b/pkix/cert_host.go index 305ef75..ea31e93 100644 --- a/pkix/cert_host.go +++ b/pkix/cert_host.go @@ -28,6 +28,12 @@ import ( // CreateCertificateHost creates certificate for host. // The arguments include CA certificate, CA key, certificate request. func CreateCertificateHost(crtAuth *Certificate, keyAuth *Key, csr *CertificateSigningRequest, proposedExpiry time.Time) (*Certificate, error) { + return CreateCertificateHostWithExtUsage(crtAuth, keyAuth, csr, proposedExpiry, nil) +} + +// CreateCertificateHostWithExtUsage creates certificate for host with optional key usage extensions. +// The arguments include CA certificate, CA key, certificate request, and any key usage extensions. +func CreateCertificateHostWithExtUsage(crtAuth *Certificate, keyAuth *Key, csr *CertificateSigningRequest, proposedExpiry time.Time, extKeyUsage []x509.ExtKeyUsage) (*Certificate, error) { // Build CA based on RFC5280 hostTemplate := x509.Certificate{ // **SHOULD** be filled in a unique number @@ -61,6 +67,10 @@ func CreateCertificateHost(crtAuth *Certificate, keyAuth *Key, csr *CertificateS PermittedDNSDomains: nil, } + if extKeyUsage != nil { + hostTemplate.ExtKeyUsage = append(hostTemplate.ExtKeyUsage, extKeyUsage...) + } + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { diff --git a/pkix/cert_host_test.go b/pkix/cert_host_test.go index b34cd0d..bb39c25 100644 --- a/pkix/cert_host_test.go +++ b/pkix/cert_host_test.go @@ -18,6 +18,8 @@ package pkix import ( + "crypto/x509" + "bytes" "testing" "time" @@ -66,4 +68,29 @@ func TestCreateCertificateHost(t *testing.T) { if err = rawCrt.CheckSignatureFrom(rawCrtAuth); err != nil { t.Fatal("Failed to check signature:", err) } + + extKeyUsage := []x509.ExtKeyUsage{ + x509.ExtKeyUsageCodeSigning, + } + cscrt, err := CreateCertificateHostWithExtUsage(crtAuth, key, csr, time.Now().AddDate(5000, 0, 0), extKeyUsage) + if err != nil { + t.Fatal("Failed creating certificate with codesigning for host:", err) + } + + csrawCrt, err := cscrt.GetRawCertificate() + if err != nil { + t.Fatal("Failed to get x509.Certificate with codesigning:", err) + } + + hasCodeSigning := false + for _, eku := range csrawCrt.ExtKeyUsage { + if eku == x509.ExtKeyUsageCodeSigning { + hasCodeSigning = true + } + } + + if !hasCodeSigning { + t.Fatal("x509.Certificate does not include codesigning extra key usage") + } + } From e73497b6d54c0599a82fe5fb2df05674c0a4b66e Mon Sep 17 00:00:00 2001 From: "Andrew E. Bruno" Date: Tue, 19 Nov 2019 11:43:15 -0500 Subject: [PATCH 2/2] Fix typo --- cmd/sign.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/sign.go b/cmd/sign.go index 0e826a1..7006712 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -69,7 +69,7 @@ func NewSignCommand() cli.Command { Usage: "Whether generated certificate should be a intermediate", }, cli.BoolFlag{ - Name: "codsigning", + Name: "codesigning", Usage: "Whether generated certificate should include the codeSigning extended key usage extension", }, },