Add public methods to retrieve the provisioner extensions.
parent
236caaa735
commit
4690fa64ed
@ -0,0 +1,73 @@
|
|||||||
|
package provisioner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// StepOIDRoot is the root OID for smallstep.
|
||||||
|
StepOIDRoot = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 37476, 9000, 64}
|
||||||
|
|
||||||
|
// StepOIDProvisioner is the OID for the provisioner extension.
|
||||||
|
StepOIDProvisioner = append(asn1.ObjectIdentifier(nil), append(StepOIDRoot, 1)...)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension is the Go representation of the provisioner extension.
|
||||||
|
type Extension struct {
|
||||||
|
Type Type
|
||||||
|
Name string
|
||||||
|
CredentialID string
|
||||||
|
KeyValuePairs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type extensionASN1 struct {
|
||||||
|
Type int
|
||||||
|
Name []byte
|
||||||
|
CredentialID []byte
|
||||||
|
KeyValuePairs []string `asn1:"optional,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals the extension using encoding/asn1.
|
||||||
|
func (e *Extension) Marshal() ([]byte, error) {
|
||||||
|
return asn1.Marshal(extensionASN1{
|
||||||
|
Type: int(e.Type),
|
||||||
|
Name: []byte(e.Name),
|
||||||
|
CredentialID: []byte(e.CredentialID),
|
||||||
|
KeyValuePairs: e.KeyValuePairs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToExtension returns the pkix.Extension representation of the provisioner
|
||||||
|
// extension.
|
||||||
|
func (e *Extension) ToExtension() (pkix.Extension, error) {
|
||||||
|
b, err := e.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return pkix.Extension{}, err
|
||||||
|
}
|
||||||
|
return pkix.Extension{
|
||||||
|
Id: StepOIDProvisioner,
|
||||||
|
Value: b,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProvisionerExtension goes through all the certificate extensions and
|
||||||
|
// returns the provisioner extension (1.3.6.1.4.1.37476.9000.64.1).
|
||||||
|
func GetProvisionerExtension(cert *x509.Certificate) (*Extension, bool) {
|
||||||
|
for _, e := range cert.Extensions {
|
||||||
|
if e.Id.Equal(StepOIDProvisioner) {
|
||||||
|
var provisioner extensionASN1
|
||||||
|
if _, err := asn1.Unmarshal(e.Value, &provisioner); err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return &Extension{
|
||||||
|
Type: Type(provisioner.Type),
|
||||||
|
Name: string(provisioner.Name),
|
||||||
|
CredentialID: string(provisioner.CredentialID),
|
||||||
|
KeyValuePairs: provisioner.KeyValuePairs,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
@ -0,0 +1,158 @@
|
|||||||
|
package provisioner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.step.sm/crypto/pemutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtension_Marshal(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
Type Type
|
||||||
|
Name string
|
||||||
|
CredentialID string
|
||||||
|
KeyValuePairs []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want []byte
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ok", fields{TypeJWK, "name", "credentialID", nil}, []byte{
|
||||||
|
0x30, 0x17, 0x02, 0x01, 0x01, 0x04, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x04, 0x0c, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
|
||||||
|
0x44,
|
||||||
|
}, false},
|
||||||
|
{"ok with pairs", fields{TypeJWK, "name", "credentialID", []string{"foo", "bar"}}, []byte{
|
||||||
|
0x30, 0x23, 0x02, 0x01, 0x01, 0x04, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x04, 0x0c, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
|
||||||
|
0x44, 0x30, 0x0a, 0x13, 0x03, 0x66, 0x6f, 0x6f,
|
||||||
|
0x13, 0x03, 0x62, 0x61, 0x72,
|
||||||
|
}, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := &Extension{
|
||||||
|
Type: tt.fields.Type,
|
||||||
|
Name: tt.fields.Name,
|
||||||
|
CredentialID: tt.fields.CredentialID,
|
||||||
|
KeyValuePairs: tt.fields.KeyValuePairs,
|
||||||
|
}
|
||||||
|
got, err := e.Marshal()
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Extension.Marshal() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Extension.Marshal() = %x, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtension_ToExtension(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
Type Type
|
||||||
|
Name string
|
||||||
|
CredentialID string
|
||||||
|
KeyValuePairs []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
want pkix.Extension
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"ok", fields{TypeJWK, "name", "credentialID", nil}, pkix.Extension{
|
||||||
|
Id: StepOIDProvisioner,
|
||||||
|
Value: []byte{
|
||||||
|
0x30, 0x17, 0x02, 0x01, 0x01, 0x04, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x04, 0x0c, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
|
||||||
|
0x44,
|
||||||
|
},
|
||||||
|
}, false},
|
||||||
|
{"ok empty pairs", fields{TypeJWK, "name", "credentialID", []string{}}, pkix.Extension{
|
||||||
|
Id: StepOIDProvisioner,
|
||||||
|
Value: []byte{
|
||||||
|
0x30, 0x17, 0x02, 0x01, 0x01, 0x04, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x04, 0x0c, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
|
||||||
|
0x44,
|
||||||
|
},
|
||||||
|
}, false},
|
||||||
|
{"ok with pairs", fields{TypeJWK, "name", "credentialID", []string{"foo", "bar"}}, pkix.Extension{
|
||||||
|
Id: StepOIDProvisioner,
|
||||||
|
Value: []byte{
|
||||||
|
0x30, 0x23, 0x02, 0x01, 0x01, 0x04, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x04, 0x0c, 0x63, 0x72, 0x65,
|
||||||
|
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49,
|
||||||
|
0x44, 0x30, 0x0a, 0x13, 0x03, 0x66, 0x6f, 0x6f,
|
||||||
|
0x13, 0x03, 0x62, 0x61, 0x72,
|
||||||
|
},
|
||||||
|
}, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
e := &Extension{
|
||||||
|
Type: tt.fields.Type,
|
||||||
|
Name: tt.fields.Name,
|
||||||
|
CredentialID: tt.fields.CredentialID,
|
||||||
|
KeyValuePairs: tt.fields.KeyValuePairs,
|
||||||
|
}
|
||||||
|
got, err := e.ToExtension()
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Extension.ToExtension() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Extension.ToExtension() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetProvisionerExtension(t *testing.T) {
|
||||||
|
mustCertificate := func(fn string) *x509.Certificate {
|
||||||
|
cert, err := pemutil.ReadCertificate(fn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return cert
|
||||||
|
}
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
cert *x509.Certificate
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *Extension
|
||||||
|
want1 bool
|
||||||
|
}{
|
||||||
|
{"ok", args{mustCertificate("testdata/certs/good-extension.crt")}, &Extension{
|
||||||
|
Type: TypeJWK,
|
||||||
|
Name: "mariano@smallstep.com",
|
||||||
|
CredentialID: "nvgnR8wSzpUlrt_tC3mvrhwhBx9Y7T1WL_JjcFVWYBQ",
|
||||||
|
}, true},
|
||||||
|
{"fail unmarshal", args{mustCertificate("testdata/certs/bad-extension.crt")}, nil, false},
|
||||||
|
{"missing extension", args{mustCertificate("testdata/certs/aws.crt")}, nil, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, got1 := GetProvisionerExtension(tt.args.cert)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("GetProvisionerExtension() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
if got1 != tt.want1 {
|
||||||
|
t.Errorf("GetProvisionerExtension() got1 = %v, want %v", got1, tt.want1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDeTCCAx+gAwIBAgIRAOTItW2pYuSU+PkmLW090iUwCgYIKoZIzj0EAwIwJDEi
|
||||||
|
MCAGA1UEAxMZU21hbGxzdGVwIEludGVybWVkaWF0ZSBDQTAeFw0yMjAzMTEyMjUy
|
||||||
|
MjBaFw0yMjAzMTIyMjUzMjBaMIGcMQswCQYDVQQGEwJDSDETMBEGA1UECBMKQ2Fs
|
||||||
|
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEYMBYGA1UECRMPMSBUaGUg
|
||||||
|
U3RyZWV0IFN0MRMwEQYDVQQKDAo8bm8gdmFsdWU+MRYwFAYDVQQLEw1TbWFsbHN0
|
||||||
|
ZXAgRW5nMRkwFwYDVQQDDBB0ZXN0QGV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI
|
||||||
|
KoZIzj0DAQcDQgAE/9vvOZ1Zzysnf3VeGyotMJEMZdAborB36Ah5QL/3yQNMRWIc
|
||||||
|
pv9Dwx19pHw7SquVE8jIaPPJSjaeWnfMPDYDxaOCAbcwggGzMA4GA1UdDwEB/wQE
|
||||||
|
AwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIw
|
||||||
|
ADAdBgNVHQ4EFgQUkJUg6AsqWlqTZt6BHidRMwh1vKYwHwYDVR0jBBgwFoAUDpTg
|
||||||
|
d3VFCn6e71wXcwbDCURBomUwgZoGCCsGAQUFBwEBBIGNMIGKMBcGCCsGAQUFBzAB
|
||||||
|
hgtodHRwczovL2ZvbzBvBggrBgEFBQcwAoZjaHR0cHM6Ly9jYS5zbWFsbHN0ZXAu
|
||||||
|
Y29tOjkwMDAvcm9vdC9hNzhhODUwMDI1YzBjMjM0Mzg1ZWRhMjNkNzE5Mjk2NGNh
|
||||||
|
NTZhYTlkNzI3ZjUzNTY1M2IwYWZiODFjMWUwNTU5MBsGA1UdEQQUMBKBEHRlc3RA
|
||||||
|
ZXhhbXBsZS5jb20wIAYDVR0gBBkwFzALBglghkgBhv1sAQEwCAYGZ4EMAQICMD8G
|
||||||
|
A1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWV2
|
||||||
|
LXNlcnZlci1nMy5jcmwwFwYMKwYBBAGCpGTGKEABBAdmb29vYmFyMAoGCCqGSM49
|
||||||
|
BAMCA0gAMEUCIQCWYqOuk4bLkVVeHvo3P8TlJJ3fw6ijDDLstvdrQqAl5wIgEjSY
|
||||||
|
wVcR649Oc8PJGh/43Kpx0+4OTYPQrD/JqphVF7g=
|
||||||
|
-----END CERTIFICATE-----
|
@ -0,0 +1,22 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDujCCA2GgAwIBAgIRAM5celDKTTqAGycljO7FZdEwCgYIKoZIzj0EAwIwJDEi
|
||||||
|
MCAGA1UEAxMZU21hbGxzdGVwIEludGVybWVkaWF0ZSBDQTAeFw0yMjAzMTEyMjQx
|
||||||
|
MDRaFw0yMjAzMTIyMjQyMDRaMIGcMQswCQYDVQQGEwJDSDETMBEGA1UECBMKQ2Fs
|
||||||
|
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEYMBYGA1UECRMPMSBUaGUg
|
||||||
|
U3RyZWV0IFN0MRMwEQYDVQQKDAo8bm8gdmFsdWU+MRYwFAYDVQQLEw1TbWFsbHN0
|
||||||
|
ZXAgRW5nMRkwFwYDVQQDDBB0ZXN0QGV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI
|
||||||
|
KoZIzj0DAQcDQgAEkXffZYlSJRMxJrZHmUpEMC4jQYCkF86mLJY0iLZ8k00N/xF0
|
||||||
|
4rAGwzTU/l9tfRpNl+z/XfMMWPXS0Q8NU/o4S6OCAfkwggH1MA4GA1UdDwEB/wQE
|
||||||
|
AwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIw
|
||||||
|
ADAdBgNVHQ4EFgQUL3sSlYW8Tf2l2P+gFTdn5wsUjfgwHwYDVR0jBBgwFoAUDpTg
|
||||||
|
d3VFCn6e71wXcwbDCURBomUwgZoGCCsGAQUFBwEBBIGNMIGKMBcGCCsGAQUFBzAB
|
||||||
|
hgtodHRwczovL2ZvbzBvBggrBgEFBQcwAoZjaHR0cHM6Ly9jYS5zbWFsbHN0ZXAu
|
||||||
|
Y29tOjkwMDAvcm9vdC9hNzhhODUwMDI1YzBjMjM0Mzg1ZWRhMjNkNzE5Mjk2NGNh
|
||||||
|
NTZhYTlkNzI3ZjUzNTY1M2IwYWZiODFjMWUwNTU5MBsGA1UdEQQUMBKBEHRlc3RA
|
||||||
|
ZXhhbXBsZS5jb20wIAYDVR0gBBkwFzALBglghkgBhv1sAQEwCAYGZ4EMAQICMD8G
|
||||||
|
A1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWV2
|
||||||
|
LXNlcnZlci1nMy5jcmwwWQYMKwYBBAGCpGTGKEABBEkwRwIBAQQVbWFyaWFub0Bz
|
||||||
|
bWFsbHN0ZXAuY29tBCtudmduUjh3U3pwVWxydF90QzNtdnJod2hCeDlZN1QxV0xf
|
||||||
|
SmpjRlZXWUJRMAoGCCqGSM49BAMCA0cAMEQCIE6umrhSbeQWWVK5cWBvXj5c0cGB
|
||||||
|
bUF0rNw/dsaCaWcwAiAKSkmjhsC63DVPXPCNUki90YgVovO69foO1ZaB43lx5w==
|
||||||
|
-----END CERTIFICATE-----
|
Loading…
Reference in New Issue