forked from TrueCloudLab/certificates
Replace instead of prepend provisioner extension
With non standard SANs this will generate the SAN and provisioner extension in the same order.
This commit is contained in:
parent
2ab1e6658e
commit
21427d5d65
2 changed files with 29 additions and 26 deletions
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -425,18 +424,6 @@ func (v *x509NamePolicyValidator) Valid(cert *x509.Certificate, _ SignOptions) e
|
||||||
return v.policyEngine.IsX509CertificateAllowed(cert)
|
return v.policyEngine.IsX509CertificateAllowed(cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
// var (
|
|
||||||
// stepOIDRoot = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 37476, 9000, 64}
|
|
||||||
// stepOIDProvisioner = append(asn1.ObjectIdentifier(nil), append(stepOIDRoot, 1)...)
|
|
||||||
// )
|
|
||||||
|
|
||||||
// type stepProvisionerASN1 struct {
|
|
||||||
// Type int
|
|
||||||
// Name []byte
|
|
||||||
// CredentialID []byte
|
|
||||||
// KeyValuePairs []string `asn1:"optional,omitempty"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
type forceCNOption struct {
|
type forceCNOption struct {
|
||||||
ForceCN bool
|
ForceCN bool
|
||||||
}
|
}
|
||||||
|
@ -481,13 +468,14 @@ func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ SignOption
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.NewError(http.StatusInternalServerError, err, "error creating certificate")
|
return errs.NewError(http.StatusInternalServerError, err, "error creating certificate")
|
||||||
}
|
}
|
||||||
// Prepend the provisioner extension. In the auth.Sign code we will
|
// Replace or append the provisioner extension to avoid the inclusions of
|
||||||
// force the resulting certificate to only have one extension, the
|
// malicious stepOIDProvisioner using templates.
|
||||||
// first stepOIDProvisioner that is found in the ExtraExtensions.
|
for i, e := range cert.ExtraExtensions {
|
||||||
// A client could pass a csr containing a malicious stepOIDProvisioner
|
if e.Id.Equal(StepOIDProvisioner) {
|
||||||
// ExtraExtension. If we were to append (rather than prepend) the correct
|
cert.ExtraExtensions[i] = ext
|
||||||
// stepOIDProvisioner extension, then the resulting certificate would
|
return nil
|
||||||
// contain the malicious extension, rather than the one applied by step-ca.
|
}
|
||||||
cert.ExtraExtensions = append([]pkix.Extension{ext}, cert.ExtraExtensions...)
|
}
|
||||||
|
cert.ExtraExtensions = append(cert.ExtraExtensions, ext)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package provisioner
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -625,6 +626,16 @@ func Test_profileDefaultDuration_Option(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_newProvisionerExtension_Option(t *testing.T) {
|
func Test_newProvisionerExtension_Option(t *testing.T) {
|
||||||
|
expectedValue, err := asn1.Marshal(extensionASN1{
|
||||||
|
Type: int(TypeJWK),
|
||||||
|
Name: []byte("name"),
|
||||||
|
CredentialID: []byte("credentialId"),
|
||||||
|
KeyValuePairs: []string{"key", "value"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
cert *x509.Certificate
|
cert *x509.Certificate
|
||||||
valid func(*x509.Certificate)
|
valid func(*x509.Certificate)
|
||||||
|
@ -636,18 +647,22 @@ func Test_newProvisionerExtension_Option(t *testing.T) {
|
||||||
valid: func(cert *x509.Certificate) {
|
valid: func(cert *x509.Certificate) {
|
||||||
if assert.Len(t, 1, cert.ExtraExtensions) {
|
if assert.Len(t, 1, cert.ExtraExtensions) {
|
||||||
ext := cert.ExtraExtensions[0]
|
ext := cert.ExtraExtensions[0]
|
||||||
assert.Equals(t, ext.Id, StepOIDProvisioner)
|
assert.Equals(t, StepOIDProvisioner, ext.Id)
|
||||||
|
assert.Equals(t, expectedValue, ext.Value)
|
||||||
|
assert.False(t, ext.Critical)
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ok/prepend": func() test {
|
"ok/replace": func() test {
|
||||||
return test{
|
return test{
|
||||||
cert: &x509.Certificate{ExtraExtensions: []pkix.Extension{{Id: StepOIDProvisioner, Critical: true}, {Id: []int{1, 2, 3}}}},
|
cert: &x509.Certificate{ExtraExtensions: []pkix.Extension{{Id: StepOIDProvisioner, Critical: true}, {Id: []int{1, 2, 3}}}},
|
||||||
valid: func(cert *x509.Certificate) {
|
valid: func(cert *x509.Certificate) {
|
||||||
if assert.Len(t, 3, cert.ExtraExtensions) {
|
if assert.Len(t, 2, cert.ExtraExtensions) {
|
||||||
ext := cert.ExtraExtensions[0]
|
ext := cert.ExtraExtensions[0]
|
||||||
assert.Equals(t, ext.Id, StepOIDProvisioner)
|
assert.Equals(t, StepOIDProvisioner, ext.Id)
|
||||||
|
assert.Equals(t, expectedValue, ext.Value)
|
||||||
assert.False(t, ext.Critical)
|
assert.False(t, ext.Critical)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -657,7 +672,7 @@ func Test_newProvisionerExtension_Option(t *testing.T) {
|
||||||
for name, run := range tests {
|
for name, run := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
tt := run()
|
tt := run()
|
||||||
assert.FatalError(t, newProvisionerExtensionOption(TypeJWK, "foo", "bar", "baz", "zap").Modify(tt.cert, SignOptions{}))
|
assert.FatalError(t, newProvisionerExtensionOption(TypeJWK, "name", "credentialId", "key", "value").Modify(tt.cert, SignOptions{}))
|
||||||
tt.valid(tt.cert)
|
tt.valid(tt.cert)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue