certificates/x509util/options_test.go
2020-07-21 14:21:54 -07:00

237 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)
}
})
}
}