forked from TrueCloudLab/certificates
238 lines
7.5 KiB
Go
238 lines
7.5 KiB
Go
|
package x509util
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto"
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/x509"
|
||
|
"crypto/x509/pkix"
|
||
|
"encoding/base64"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
func createRSACertificateRequest(t *testing.T, bits int, commonName string, sans []string) (*x509.CertificateRequest, crypto.Signer) {
|
||
|
dnsNames, ips, emails, uris := SplitSANs(sans)
|
||
|
t.Helper()
|
||
|
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
asn1Data, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
|
||
|
Subject: pkix.Name{CommonName: commonName},
|
||
|
DNSNames: dnsNames,
|
||
|
IPAddresses: ips,
|
||
|
EmailAddresses: emails,
|
||
|
URIs: uris,
|
||
|
SignatureAlgorithm: x509.SHA256WithRSAPSS,
|
||
|
}, priv)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
cr, err := x509.ParseCertificateRequest(asn1Data)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
return cr, priv
|
||
|
}
|
||
|
|
||
|
func Test_getFuncMap_fail(t *testing.T) {
|
||
|
var failMesage string
|
||
|
fns := getFuncMap(&failMesage)
|
||
|
fail := fns["fail"].(func(s string) (string, error))
|
||
|
s, err := fail("the fail message")
|
||
|
if err == nil {
|
||
|
t.Errorf("fail() error = %v, wantErr %v", err, errors.New("the fail message"))
|
||
|
}
|
||
|
if s != "" {
|
||
|
t.Errorf("fail() = \"%s\", want \"the fail message\"", s)
|
||
|
}
|
||
|
if failMesage != "the fail message" {
|
||
|
t.Errorf("fail() message = \"%s\", want \"the fail message\"", failMesage)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestWithTemplate(t *testing.T) {
|
||
|
cr, _ := createCertificateRequest(t, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
crRSA, _ := createRSACertificateRequest(t, 2048, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
type args struct {
|
||
|
text string
|
||
|
data TemplateData
|
||
|
cr *x509.CertificateRequest
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
want Options
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{"leaf", args{DefaultLeafTemplate, TemplateData{
|
||
|
SubjectKey: Subject{CommonName: "foo"},
|
||
|
SANsKey: []SubjectAlternativeName{{Type: "dns", Value: "foo.com"}},
|
||
|
}, cr}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"}],
|
||
|
"keyUsage": ["digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"leafRSA", args{DefaultLeafTemplate, TemplateData{
|
||
|
SubjectKey: Subject{CommonName: "foo"},
|
||
|
SANsKey: []SubjectAlternativeName{{Type: "dns", Value: "foo.com"}},
|
||
|
}, crRSA}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"}],
|
||
|
"keyUsage": ["keyEncipherment", "digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"iid", args{DefaultIIDLeafTemplate, TemplateData{}, cr}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"dnsNames": ["foo.com"],
|
||
|
"emailAddresses": ["foo@foo.com"],
|
||
|
"ipAddresses": ["::1"],
|
||
|
"uris": ["https://foo.com"],
|
||
|
"keyUsage": ["digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"iidRSAAndEnforced", args{DefaultIIDLeafTemplate, TemplateData{
|
||
|
SANsKey: []SubjectAlternativeName{{Type: "dns", Value: "foo.com"}},
|
||
|
}, crRSA}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"}],
|
||
|
"keyUsage": ["keyEncipherment", "digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"fail", args{`{{ fail "a message" }}`, TemplateData{}, cr}, Options{}, true},
|
||
|
{"error", args{`{{ mustHas 3 .Data }}`, TemplateData{
|
||
|
"Data": 3,
|
||
|
}, cr}, Options{}, true},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
var got Options
|
||
|
fn := WithTemplate(tt.args.text, tt.args.data)
|
||
|
if err := fn(tt.args.cr, &got); (err != nil) != tt.wantErr {
|
||
|
t.Errorf("WithTemplate() error = %v, wantErr %v", err, tt.wantErr)
|
||
|
}
|
||
|
if !reflect.DeepEqual(got, tt.want) {
|
||
|
t.Errorf("WithTemplate() = %v, want %v", got, tt.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestWithTemplateBase64(t *testing.T) {
|
||
|
cr, _ := createCertificateRequest(t, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
type args struct {
|
||
|
s string
|
||
|
data TemplateData
|
||
|
cr *x509.CertificateRequest
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
want Options
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{"leaf", args{base64.StdEncoding.EncodeToString([]byte(DefaultLeafTemplate)), TemplateData{
|
||
|
SubjectKey: Subject{CommonName: "foo"},
|
||
|
SANsKey: []SubjectAlternativeName{{Type: "dns", Value: "foo.com"}},
|
||
|
}, cr}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"}],
|
||
|
"keyUsage": ["digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"badBase64", args{"foobar", TemplateData{}, cr}, Options{}, true},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
var got Options
|
||
|
fn := WithTemplateBase64(tt.args.s, tt.args.data)
|
||
|
if err := fn(tt.args.cr, &got); (err != nil) != tt.wantErr {
|
||
|
t.Errorf("WithTemplateBase64() error = %v, wantErr %v", err, tt.wantErr)
|
||
|
}
|
||
|
if !reflect.DeepEqual(got, tt.want) {
|
||
|
t.Errorf("WithTemplateBase64() = %v, want %v", got, tt.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestWithTemplateFile(t *testing.T) {
|
||
|
cr, _ := createCertificateRequest(t, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
rsa2048, _ := createRSACertificateRequest(t, 2048, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
rsa3072, _ := createRSACertificateRequest(t, 3072, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
|
||
|
|
||
|
data := TemplateData{
|
||
|
SANsKey: []SubjectAlternativeName{
|
||
|
{Type: "dns", Value: "foo.com"},
|
||
|
{Type: "email", Value: "root@foo.com"},
|
||
|
{Type: "ip", Value: "127.0.0.1"},
|
||
|
{Type: "uri", Value: "uri:foo:bar"},
|
||
|
},
|
||
|
TokenKey: map[string]interface{}{
|
||
|
"iss": "https://iss",
|
||
|
"sub": "sub",
|
||
|
},
|
||
|
}
|
||
|
type args struct {
|
||
|
path string
|
||
|
data TemplateData
|
||
|
cr *x509.CertificateRequest
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
want Options
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{"example", args{"./testdata/example.tpl", data, cr}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"},{"type":"email","value":"root@foo.com"},{"type":"ip","value":"127.0.0.1"},{"type":"uri","value":"uri:foo:bar"}],
|
||
|
"emailAddresses": ["foo@foo.com"],
|
||
|
"uris": "https://iss#sub",
|
||
|
"keyUsage": ["digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"exampleRSA3072", args{"./testdata/example.tpl", data, rsa3072}, Options{
|
||
|
CertBuffer: bytes.NewBufferString(`{
|
||
|
"subject": {"commonName":"foo"},
|
||
|
"sans": [{"type":"dns","value":"foo.com"},{"type":"email","value":"root@foo.com"},{"type":"ip","value":"127.0.0.1"},{"type":"uri","value":"uri:foo:bar"}],
|
||
|
"emailAddresses": ["foo@foo.com"],
|
||
|
"uris": "https://iss#sub",
|
||
|
"keyUsage": ["keyEncipherment", "digitalSignature"],
|
||
|
"extKeyUsage": ["serverAuth", "clientAuth"]
|
||
|
}`),
|
||
|
}, false},
|
||
|
{"exampleRSA2048", args{"./testdata/example.tpl", data, rsa2048}, Options{}, true},
|
||
|
{"missing", args{"./testdata/missing.tpl", data, cr}, Options{}, true},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
var got Options
|
||
|
fn := WithTemplateFile(tt.args.path, tt.args.data)
|
||
|
if err := fn(tt.args.cr, &got); (err != nil) != tt.wantErr {
|
||
|
t.Errorf("WithTemplateFile() error = %v, wantErr %v", err, tt.wantErr)
|
||
|
}
|
||
|
if !reflect.DeepEqual(got, tt.want) {
|
||
|
t.Errorf("WithTemplateFile() = %v, want %v", got, tt.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|