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