зеркало из https://github.com/github/smimesign.git
ommit issuer by default if cert has AIA
this adds a new --include-certs=-3 option (default) that includes the chain except for the root (as per gpgsm). The difference is that each issuer in the chain will be omitted if the cert has the AIA extension specifying where to download the issuer.
This commit is contained in:
Родитель
59baa0932a
Коммит
b7cd4ea23c
|
@ -34,7 +34,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/mastahyeti/fakeca"
|
||||
packages = ["."]
|
||||
revision = "cb55136fa97a78a6e6cf8bdc483c30fe2eb562e6"
|
||||
revision = "5f91b32d1226951f9631342eee20f5142387a216"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
|
@ -122,11 +122,21 @@ func findUserIdentity() (certstore.Identity, error) {
|
|||
// certsForSignature determines which certificates to include in the signature
|
||||
// based on the --include-certs option specified by the user.
|
||||
func certsForSignature(chain []*x509.Certificate) []*x509.Certificate {
|
||||
if *includeCertsOpt <= -2 {
|
||||
if hasRoot := bytes.Equal(chain[len(chain)-1].RawIssuer, chain[len(chain)-1].RawSubject); hasRoot {
|
||||
return chain[0 : len(chain)-1]
|
||||
if *includeCertsOpt <= -3 {
|
||||
for i := len(chain) - 1; i > 0; i-- {
|
||||
issuer, cert := chain[i], chain[i-1]
|
||||
|
||||
// remove issuer when cert has AIA extension
|
||||
if bytes.Equal(issuer.RawSubject, cert.RawIssuer) && len(cert.IssuingCertificateURL) > 0 {
|
||||
chain = chain[0:i]
|
||||
}
|
||||
}
|
||||
return chain
|
||||
|
||||
return chainWithoutRoot(chain)
|
||||
}
|
||||
|
||||
if *includeCertsOpt == -2 {
|
||||
return chainWithoutRoot(chain)
|
||||
}
|
||||
|
||||
if *includeCertsOpt == -1 {
|
||||
|
@ -140,3 +150,21 @@ func certsForSignature(chain []*x509.Certificate) []*x509.Certificate {
|
|||
|
||||
return chain[0:include]
|
||||
}
|
||||
|
||||
// Returns the provided chain, having removed the root certificate, if present.
|
||||
// This includes removing the cert itself if the chain is a single self-signed
|
||||
// cert.
|
||||
func chainWithoutRoot(chain []*x509.Certificate) []*x509.Certificate {
|
||||
if len(chain) == 0 {
|
||||
return chain
|
||||
}
|
||||
|
||||
lastIdx := len(chain) - 1
|
||||
last := chain[lastIdx]
|
||||
|
||||
if bytes.Equal(last.RawIssuer, last.RawSubject) {
|
||||
return chain[0:lastIdx]
|
||||
}
|
||||
|
||||
return chain
|
||||
}
|
||||
|
|
|
@ -21,6 +21,25 @@ func TestSign(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSignIncludeCertsAIA(t *testing.T) {
|
||||
defer testSetup(t, "--sign", "-u", certHexFingerprint(aiaLeaf.Certificate))()
|
||||
|
||||
stdinBuf.WriteString("hello, world!")
|
||||
commandSign()
|
||||
|
||||
ci, err := protocol.ParseContentInfo(stdoutBuf.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
sd, err := ci.SignedDataContent()
|
||||
require.NoError(t, err)
|
||||
|
||||
certs, err := sd.X509Certificates()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 1, len(certs))
|
||||
require.True(t, certs[0].Equal(aiaLeaf.Certificate))
|
||||
}
|
||||
|
||||
func TestSignIncludeCertsDefault(t *testing.T) {
|
||||
defer testSetup(t, "--sign", "-u", certHexFingerprint(leaf.Certificate))()
|
||||
|
||||
|
@ -41,6 +60,26 @@ func TestSignIncludeCertsDefault(t *testing.T) {
|
|||
require.True(t, certs[1].Equal(intermediate.Certificate))
|
||||
}
|
||||
|
||||
func TestSignIncludeCertsMinus3(t *testing.T) {
|
||||
defer testSetup(t, "--sign", "--include-certs=-3", "-u", certHexFingerprint(leaf.Certificate))()
|
||||
|
||||
stdinBuf.WriteString("hello, world!")
|
||||
commandSign()
|
||||
|
||||
ci, err := protocol.ParseContentInfo(stdoutBuf.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
sd, err := ci.SignedDataContent()
|
||||
require.NoError(t, err)
|
||||
|
||||
certs, err := sd.X509Certificates()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 2, len(certs))
|
||||
require.True(t, certs[0].Equal(leaf.Certificate))
|
||||
require.True(t, certs[1].Equal(intermediate.Certificate))
|
||||
}
|
||||
|
||||
func TestSignIncludeCertsMinus2(t *testing.T) {
|
||||
defer testSetup(t, "--sign", "--include-certs=-2", "-u", certHexFingerprint(leaf.Certificate))()
|
||||
|
||||
|
|
2
main.go
2
main.go
|
@ -28,7 +28,7 @@ var (
|
|||
statusFdOpt = getopt.IntLong("status-fd", 0, -1, "write special status strings to the file descriptor n.", "n")
|
||||
keyFormatOpt = getopt.EnumLong("keyid-format", 0, []string{"long"}, "long", "select how to display key IDs.", "{long}")
|
||||
tsaOpt = getopt.StringLong("timestamp-authority", 't', defaultTSA, "URL of RFC3161 timestamp authority to use for timestamping")
|
||||
includeCertsOpt = getopt.IntLong("include-certs", 0, -2, "-2 includes all certs except root. -1 includes all certs. 0 includes no certs. 1 includes leaf cert. >1 includes n from the leaf. Default -2.")
|
||||
includeCertsOpt = getopt.IntLong("include-certs", 0, -3, "-3 is the same as -2, but ommits issuer when cert has Authority Information Access extension. -2 includes all certs except root. -1 includes all certs. 0 includes no certs. 1 includes leaf cert. >1 includes n from the leaf. Default -3.")
|
||||
|
||||
// Remaining arguments
|
||||
fileArgs []string
|
||||
|
|
10
main_test.go
10
main_test.go
|
@ -17,7 +17,10 @@ var (
|
|||
ca = fakeca.New(fakeca.IsCA)
|
||||
intermediate = ca.Issue(fakeca.IsCA)
|
||||
leaf = intermediate.Issue()
|
||||
wrappedLeaf = identity{leaf}
|
||||
aiaLeaf = intermediate.Issue(fakeca.IssuingCertificateURL("http://foo"))
|
||||
|
||||
wrappedLeaf = identity{leaf}
|
||||
wrappedAIALeaf = identity{aiaLeaf}
|
||||
)
|
||||
|
||||
// make *fakeca.Identity implement certstore.Identity
|
||||
|
@ -100,7 +103,10 @@ func testSetup(t *testing.T, args ...string) func() {
|
|||
|
||||
getopt.CommandLine.Parse(append([]string{"smimesign"}, args...))
|
||||
|
||||
idents = []certstore.Identity{wrappedLeaf}
|
||||
idents = []certstore.Identity{
|
||||
wrappedLeaf,
|
||||
wrappedAIALeaf,
|
||||
}
|
||||
|
||||
return resetFunc
|
||||
}
|
||||
|
|
|
@ -13,13 +13,15 @@ import (
|
|||
)
|
||||
|
||||
type configuration struct {
|
||||
subject *pkix.Name
|
||||
issuer *Identity
|
||||
nextSN *int64
|
||||
priv *crypto.Signer
|
||||
isCA bool
|
||||
notBefore *time.Time
|
||||
notAfter *time.Time
|
||||
subject *pkix.Name
|
||||
issuer *Identity
|
||||
nextSN *int64
|
||||
priv *crypto.Signer
|
||||
isCA bool
|
||||
notBefore *time.Time
|
||||
notAfter *time.Time
|
||||
issuingCertificateURL []string
|
||||
ocspServer []string
|
||||
}
|
||||
|
||||
func (c *configuration) generate() *Identity {
|
||||
|
@ -29,6 +31,8 @@ func (c *configuration) generate() *Identity {
|
|||
BasicConstraintsValid: true,
|
||||
NotAfter: c.getNotAfter(),
|
||||
NotBefore: c.getNotBefore(),
|
||||
IssuingCertificateURL: c.issuingCertificateURL,
|
||||
OCSPServer: c.ocspServer,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -206,6 +210,21 @@ func NotAfter(value time.Time) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// IssuingCertificateURL is an Option for setting the identity's certificate's
|
||||
// IssuingCertificateURL.
|
||||
func IssuingCertificateURL(value ...string) Option {
|
||||
return func(c *configuration) {
|
||||
c.issuingCertificateURL = append(c.issuingCertificateURL, value...)
|
||||
}
|
||||
}
|
||||
|
||||
// OCSPServer is an Option for setting the identity's certificate's OCSPServer.
|
||||
func OCSPServer(value ...string) Option {
|
||||
return func(c *configuration) {
|
||||
c.ocspServer = append(c.ocspServer, value...)
|
||||
}
|
||||
}
|
||||
|
||||
// IsCA is an Option for making an identity a certificate authority.
|
||||
var IsCA Option = func(c *configuration) {
|
||||
c.isCA = true
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -154,6 +155,18 @@ func TestPFX(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAIA(t *testing.T) {
|
||||
i := New(IssuingCertificateURL("a", "b"), OCSPServer("c", "d"))
|
||||
|
||||
if !reflect.DeepEqual(i.Certificate.IssuingCertificateURL, []string{"a", "b"}) {
|
||||
t.Error("bad IssuingCertificateURL: ", i.Certificate.IssuingCertificateURL)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(i.Certificate.OCSPServer, []string{"c", "d"}) {
|
||||
t.Error("bad OCSPServer: ", i.Certificate.OCSPServer)
|
||||
}
|
||||
}
|
||||
|
||||
func assertNoPanic(t *testing.T, cb func()) {
|
||||
// Check that t.Helper() is defined for Go<1.9
|
||||
if h, ok := interface{}(t).(interface{ Helper() }); ok {
|
||||
|
|
Загрузка…
Ссылка в новой задаче