diff --git a/Makefile b/Makefile index b4632eef..870ad000 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SRC=$(shell find . -type f -name '*.go' -not -path "./vendor/*") GOOS_OVERRIDE ?= OUTPUT_ROOT=output/ -all: build test lint +all: lint build test .PHONY: all diff --git a/authority/tls_test.go b/authority/tls_test.go index e8a0497b..2e44c414 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -357,10 +357,9 @@ ZYtQ9Ot36qc= []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"}) - pubBytes, err := x509.MarshalPKIXPublicKey(pub) + kid, err := generateSubjectKeyID(pub) assert.FatalError(t, err) - hash := sha1.Sum(pubBytes) - assert.Equals(t, leaf.SubjectKeyId, hash[:]) + assert.Equals(t, leaf.SubjectKeyId, kid) assert.Equals(t, leaf.AuthorityKeyId, a.x509Issuer.SubjectKeyId) @@ -397,6 +396,31 @@ ZYtQ9Ot36qc= } } +// subjectPublicKeyInfo is a PKIX public key structure defined in RFC 5280. +type subjectPublicKeyInfo struct { + Algorithm pkix.AlgorithmIdentifier + SubjectPublicKey asn1.BitString +} + +// generateSubjectKeyID generates the key identifier according the the RFC 5280 +// section 4.2.1.2. +// +// The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the +// BIT STRING subjectPublicKey (excluding the tag, length, and number of unused +// bits). +func generateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) { + b, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, errors.Wrap(err, "error marshaling public key") + } + var info subjectPublicKeyInfo + if _, err = asn1.Unmarshal(b, &info); err != nil { + return nil, errors.Wrap(err, "error unmarshaling public key") + } + hash := sha1.Sum(info.SubjectPublicKey.Bytes) + return hash[:], nil +} + func TestAuthority_Renew(t *testing.T) { pub, _, err := keys.GenerateDefaultKeyPair() assert.FatalError(t, err) @@ -554,10 +578,9 @@ func TestAuthority_Renew(t *testing.T) { // Test Public Key and SubjectKeyId assert.Equals(t, leaf.PublicKey, cert.PublicKey) - pubBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) + kid, err := generateSubjectKeyID(cert.PublicKey) assert.FatalError(t, err) - hash := sha1.Sum(pubBytes) - assert.Equals(t, leaf.SubjectKeyId, hash[:]) + assert.Equals(t, leaf.SubjectKeyId, kid) assert.Equals(t, leaf.SubjectKeyId, cert.SubjectKeyId) // We did not change the intermediate before renewing. @@ -791,10 +814,9 @@ func TestAuthority_Rekey(t *testing.T) { } assert.Equals(t, leaf.PublicKey, expectedPK) - pubBytes, err := x509.MarshalPKIXPublicKey(expectedPK) + kid, err := generateSubjectKeyID(expectedPK) assert.FatalError(t, err) - hash := sha1.Sum(pubBytes) - assert.Equals(t, leaf.SubjectKeyId, hash[:]) + assert.Equals(t, leaf.SubjectKeyId, kid) if tc.pk == nil { assert.Equals(t, leaf.SubjectKeyId, cert.SubjectKeyId) } diff --git a/ca/ca_test.go b/ca/ca_test.go index 1aaed206..568e7917 100644 --- a/ca/ca_test.go +++ b/ca/ca_test.go @@ -2,11 +2,13 @@ package ca import ( "bytes" + "crypto" "crypto/rand" "crypto/sha1" "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "encoding/asn1" "encoding/json" "encoding/pem" "fmt" @@ -32,6 +34,31 @@ import ( "gopkg.in/square/go-jose.v2/jwt" ) +// subjectPublicKeyInfo is a PKIX public key structure defined in RFC 5280. +type subjectPublicKeyInfo struct { + Algorithm pkix.AlgorithmIdentifier + SubjectPublicKey asn1.BitString +} + +// generateSubjectKeyID generates the key identifier according the the RFC 5280 +// section 4.2.1.2. +// +// The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the +// BIT STRING subjectPublicKey (excluding the tag, length, and number of unused +// bits). +func generateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) { + b, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, errors.Wrap(err, "error marshaling public key") + } + var info subjectPublicKeyInfo + if _, err = asn1.Unmarshal(b, &info); err != nil { + return nil, errors.Wrap(err, "error unmarshaling public key") + } + hash := sha1.Sum(info.SubjectPublicKey.Bytes) + return hash[:], nil +} + type ClosingBuffer struct { *bytes.Buffer } @@ -299,10 +326,9 @@ ZEp7knvU2psWRw== []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) assert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"}) - pubBytes, err := x509.MarshalPKIXPublicKey(pub) + kid, err := generateSubjectKeyID(pub) assert.FatalError(t, err) - hash := sha1.Sum(pubBytes) - assert.Equals(t, leaf.SubjectKeyId, hash[:]) + assert.Equals(t, leaf.SubjectKeyId, kid) assert.Equals(t, leaf.AuthorityKeyId, intermediateIdentity.Crt.SubjectKeyId) @@ -641,10 +667,9 @@ func TestCARenew(t *testing.T) { []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) assert.Equals(t, leaf.DNSNames, []string{"funk"}) - pubBytes, err := x509.MarshalPKIXPublicKey(pub) + kid, err := generateSubjectKeyID(pub) assert.FatalError(t, err) - hash := sha1.Sum(pubBytes) - assert.Equals(t, leaf.SubjectKeyId, hash[:]) + assert.Equals(t, leaf.SubjectKeyId, kid) assert.Equals(t, leaf.AuthorityKeyId, intermediateIdentity.Crt.SubjectKeyId) diff --git a/go.mod b/go.mod index 9df83f5d..96dfd661 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/rs/xid v1.2.1 github.com/sirupsen/logrus v1.4.2 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 - github.com/smallstep/cli v0.14.6 + github.com/smallstep/cli v0.14.7-rc.1.0.20200727165646-eb4e97335f2d github.com/smallstep/nosql v0.3.0 github.com/urfave/cli v1.22.2 golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 diff --git a/go.sum b/go.sum index 92918917..264f7505 100644 --- a/go.sum +++ b/go.sum @@ -476,9 +476,12 @@ github.com/smallstep/cli v0.14.5 h1:avA6q9h2aIbAQa/vTFV5psjJ1mg8NQliKC+RsFIC778= github.com/smallstep/cli v0.14.5/go.mod h1:mRFuqC3cGwQESBGJvog4o76jZZZ7bMjkE+hAnq2QyR8= github.com/smallstep/cli v0.14.6 h1:xc9rawDKB70Vgvg10gfQAh9EpDWS3k1O002J5bApqUk= github.com/smallstep/cli v0.14.6/go.mod h1:Gs9mXwk5tIBlSISt1tvCAMso7eEAiJRyNgR/6JsoojI= +github.com/smallstep/cli v0.14.7-rc.1.0.20200727165646-eb4e97335f2d h1:bDnvzyEXzAMO5in8QHRrQCEUopiXjFVKHiR8c0m7Iww= +github.com/smallstep/cli v0.14.7-rc.1.0.20200727165646-eb4e97335f2d/go.mod h1:7aWHk7WwJMpEP4PYyav86FMpaI9vuA0uJRliUAqCwxg= github.com/smallstep/nosql v0.3.0 h1:V1X5vfDsDt89499h3jZFUlR4VnnsYYs5tXaQZ0w8z5U= github.com/smallstep/nosql v0.3.0/go.mod h1:QG7gNOpidifn99MjZaiNbm7HPesIyBd97F/OfacNz8Q= github.com/smallstep/truststore v0.9.3/go.mod h1:PRSkpRIhAYBK/KLWkHNgRdYgzWMEy45bN7PSJCfKKGE= +github.com/smallstep/truststore v0.9.6/go.mod h1:HwHKRcBi0RUxxw1LYDpTRhYC4jZUuxPpkHdVonlkoDM= github.com/smallstep/zcrypto v0.0.0-20200203191936-fbc32cf76bce/go.mod h1:+F24VU3UCxfVFvvqgm5jNUFQOm/L6ed13ImwWGFgg/g= github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f/go.mod h1:GeHHT7sJDI9ti3oEaFnvx1F4N8n3ZSw2YM1+sbEoxc4= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -805,6 +808,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=