diff --git a/cmd/oid.go b/cmd/oid.go new file mode 100644 index 0000000..e620bc0 --- /dev/null +++ b/cmd/oid.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "encoding/asn1" + "strconv" + "strings" +) + +func parseOid(oid string) (asn1.ObjectIdentifier, error) { + result := make([]int, 0) + for _, part := range strings.Split(oid, ".") { + number, err := strconv.ParseInt(part, 10, 32) + if err != nil { + return asn1.ObjectIdentifier{}, err + } + result = append(result, int(number)) + } + + return asn1.ObjectIdentifier(result), nil +} diff --git a/cmd/oid_test.go b/cmd/oid_test.go new file mode 100644 index 0000000..1ad8103 --- /dev/null +++ b/cmd/oid_test.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "encoding/asn1" + "testing" +) + +func TestValidOid(t *testing.T) { + parsed, _ := parseOid("1.3.6.1.5.5.7.3.1") + expected := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} + + if !parsed.Equal(expected) { + t.Fatalf("Parsed OID does not match expected (expected: %s, got %s)", expected, parsed) + } +} + +func TestInvalidOid(t *testing.T) { + _, err := parseOid("not an OID") + if err == nil { + t.Fatalf("Expected error when parsing invalid OID") + } +} diff --git a/cmd/revoke_test.go b/cmd/revoke_test.go index c96b0a7..447fcce 100644 --- a/cmd/revoke_test.go +++ b/cmd/revoke_test.go @@ -113,7 +113,7 @@ func setupCN(t *testing.T, dt depot.Depot) { t.Fatalf("could not get cert: %v", err) } - cnCert, err := pkix.CreateCertificateHost(caCert, key, csr, time.Now().Add(1*time.Hour)) + cnCert, err := pkix.CreateCertificateHost(caCert, key, csr, time.Now().Add(1*time.Hour), nil) if err != nil { t.Fatalf("could not create cert host: %v", err) } diff --git a/cmd/sign.go b/cmd/sign.go index a1d19e7..4ebb06a 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -18,6 +18,7 @@ package cmd import ( + "encoding/asn1" "fmt" "os" "strings" @@ -67,6 +68,10 @@ func NewSignCommand() cli.Command { Name: "intermediate", Usage: "Whether generated certificate should be a intermediate", }, + cli.StringFlag{ + Name: "extended-key-usage", + Usage: "OID of additional Extended Key Usage value to add to the certificate (example: 1.3.6.1.5.5.7.3.1)", + }, }, Action: newSignAction, } @@ -99,6 +104,17 @@ func newSignAction(c *cli.Context) { os.Exit(1) } + additionalExtendedKeyUsages := make([]asn1.ObjectIdentifier, 0) + additionalExtendedKeyUsage := c.String("extended-key-usage") + if additionalExtendedKeyUsage != "" { + oid, err := parseOid(additionalExtendedKeyUsage) + if err != nil { + fmt.Fprintln(os.Stderr, "Invalid OID value:", err) + os.Exit(1) + } + additionalExtendedKeyUsages = append(additionalExtendedKeyUsages, oid) + } + csr, err := getCertificateSigningRequest(c, d, formattedReqName) if err != nil { fmt.Fprintln(os.Stderr, "Get certificate request error:", err) @@ -142,7 +158,7 @@ func newSignAction(c *cli.Context) { fmt.Fprintln(os.Stderr, "Building intermediate") crtOut, err = pkix.CreateIntermediateCertificateAuthority(crt, key, csr, expiresTime) } else { - crtOut, err = pkix.CreateCertificateHost(crt, key, csr, expiresTime) + crtOut, err = pkix.CreateCertificateHost(crt, key, csr, expiresTime, additionalExtendedKeyUsages) } if err != nil { diff --git a/pkix/cert_host.go b/pkix/cert_host.go index 305ef75..a223dca 100644 --- a/pkix/cert_host.go +++ b/pkix/cert_host.go @@ -21,13 +21,14 @@ import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" + "encoding/asn1" "math/big" "time" ) // 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) { +func CreateCertificateHost(crtAuth *Certificate, keyAuth *Key, csr *CertificateSigningRequest, proposedExpiry time.Time, extendedKeyUsages []asn1.ObjectIdentifier) (*Certificate, error) { // Build CA based on RFC5280 hostTemplate := x509.Certificate{ // **SHOULD** be filled in a unique number @@ -45,7 +46,7 @@ func CreateCertificateHost(crtAuth *Certificate, keyAuth *Key, csr *CertificateS x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth, }, - UnknownExtKeyUsage: nil, + UnknownExtKeyUsage: extendedKeyUsages, BasicConstraintsValid: false, diff --git a/pkix/cert_host_test.go b/pkix/cert_host_test.go index b34cd0d..68cdf69 100644 --- a/pkix/cert_host_test.go +++ b/pkix/cert_host_test.go @@ -39,7 +39,7 @@ func TestCreateCertificateHost(t *testing.T) { t.Fatal("Failed parsing certificate request from PEM:", err) } - crt, err := CreateCertificateHost(crtAuth, key, csr, time.Now().AddDate(5000, 0, 0)) + crt, err := CreateCertificateHost(crtAuth, key, csr, time.Now().AddDate(5000, 0, 0), nil) if err != nil { t.Fatal("Failed creating certificate for host:", err) }