diff --git a/x509util/certificate.go b/x509util/certificate.go index 69eb5378..a1d8fe18 100644 --- a/x509util/certificate.go +++ b/x509util/certificate.go @@ -17,6 +17,7 @@ import ( type Certificate struct { Version int `json:"version"` Subject Subject `json:"subject"` + RawSubject []byte `json:"rawSubject"` Issuer Issuer `json:"issuer"` SerialNumber SerialNumber `json:"serialNumber"` DNSNames MultiString `json:"dnsNames"` @@ -128,6 +129,7 @@ func (c *Certificate) GetCertificate() *x509.Certificate { // Unparsed data cert.PublicKey = c.PublicKey cert.PublicKeyAlgorithm = c.PublicKeyAlgorithm + cert.RawSubject = c.RawSubject // Subject c.Subject.Set(cert) diff --git a/x509util/certificate_request.go b/x509util/certificate_request.go index 24861e04..b2ade54a 100644 --- a/x509util/certificate_request.go +++ b/x509util/certificate_request.go @@ -45,6 +45,7 @@ type certificateRequest struct { type CertificateRequest struct { Version int `json:"version"` Subject Subject `json:"subject"` + RawSubject []byte `json:"rawSubject"` DNSNames MultiString `json:"dnsNames"` EmailAddresses MultiString `json:"emailAddresses"` IPAddresses MultiIP `json:"ipAddresses"` @@ -115,6 +116,7 @@ func NewCertificateRequestFromX509(cr *x509.CertificateRequest) *CertificateRequ return &CertificateRequest{ Version: cr.Version, Subject: newSubject(cr.Subject), + RawSubject: cr.RawSubject, DNSNames: cr.DNSNames, EmailAddresses: cr.EmailAddresses, IPAddresses: cr.IPAddresses, @@ -134,6 +136,7 @@ func (c *CertificateRequest) GetCertificateRequest() (*x509.CertificateRequest, cert := c.GetCertificate().GetCertificate() asn1Data, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{ Subject: cert.Subject, + RawSubject: cert.RawSubject, DNSNames: cert.DNSNames, IPAddresses: cert.IPAddresses, EmailAddresses: cert.EmailAddresses, diff --git a/x509util/certificate_test.go b/x509util/certificate_test.go index 7c04eaac..fa4963c9 100644 --- a/x509util/certificate_test.go +++ b/x509util/certificate_test.go @@ -22,6 +22,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.step.sm/crypto/pemutil" ) func createCertificateRequest(t *testing.T, commonName string, sans []string) (*x509.CertificateRequest, crypto.Signer) { @@ -49,6 +50,21 @@ func createCertificateRequest(t *testing.T, commonName string, sans []string) (* return cr, priv } +func readCertificateRequest(t *testing.T, filename, keyFilename string) (*x509.CertificateRequest, crypto.Signer) { + t.Helper() + + cr, err := pemutil.ReadCertificateRequest(filename) + require.NoError(t, err) + + key, err := pemutil.Read(keyFilename) + require.NoError(t, err) + + signer, ok := key.(crypto.Signer) + require.True(t, ok) + + return cr, signer +} + func createIssuerCertificate(t *testing.T, commonName string) (*x509.Certificate, crypto.Signer) { t.Helper() now := time.Now() @@ -135,6 +151,8 @@ func TestNewCertificate(t *testing.T) { return ipNet } + rawSubjectCR, rawSubjectKey := readCertificateRequest(t, "testdata/rawSubject.csr", "testdata/rawSubject.key") + type args struct { cr *x509.CertificateRequest opts []Option @@ -283,6 +301,38 @@ func TestNewCertificate(t *testing.T) { PublicKey: priv.Public(), PublicKeyAlgorithm: x509.Ed25519, }, false}, + {"okRawSubject", args{rawSubjectCR, []Option{WithTemplateFile("./testdata/rawSubject.tpl", TemplateData{ + SANsKey: []SubjectAlternativeName{ + {Type: "dns", Value: "foo.com"}, + }, + CertificateRequestKey: NewCertificateRequestFromX509(rawSubjectCR), + })}}, &Certificate{ + Subject: Subject{}, + RawSubject: []byte{ + 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, + 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x53, + 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, + 0x69, 0x73, 0x63, 0x6f, 0x31, 0x1d, 0x30, 0x1b, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x14, 0x53, + 0x6d, 0x61, 0x6c, 0x6c, 0x73, 0x74, 0x65, 0x70, + 0x20, 0x4c, 0x61, 0x62, 0x73, 0x2c, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x0d, 0x30, 0x0b, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x04, 0x54, 0x65, + 0x73, 0x74, + }, + SANs: []SubjectAlternativeName{{Type: DNSType, Value: "foo.com"}}, + KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), + ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }), + PublicKey: rawSubjectKey.Public(), + PublicKeyAlgorithm: x509.ECDSA, + }, false}, {"badSignature", args{crBadSignateure, nil}, nil, true}, {"failTemplate", args{cr, []Option{WithTemplate(`{{ fail "fatal error }}`, CreateTemplateData("commonName", []string{"foo.com"}))}}, nil, true}, {"missingTemplate", args{cr, []Option{WithTemplateFile("./testdata/missing.tpl", CreateTemplateData("commonName", []string{"foo.com"}))}}, nil, true}, diff --git a/x509util/testdata/rawSubject.csr b/x509util/testdata/rawSubject.csr new file mode 100644 index 00000000..233fcf84 --- /dev/null +++ b/x509util/testdata/rawSubject.csr @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBIjCBygIBADBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW +MBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEdMBsGA1UECgwUU21hbGxzdGVwIExhYnMs +IEluYy4xDTALBgNVBAMMBFRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATG +NLZtzv5dcl2Nz66XBV+tq5jKCH9WGPlsuBEq48NNUb1LzecjaVTZsEwe+ZpQbnzk +wTdYXFI68HbovxWc9fDxoAAwCgYIKoZIzj0EAwIDRwAwRAIgODOqVqdeZzSwZOFB +VZuSLoMVvCVoiFng8/2hXfJWJi4CIBNHEt9batonI4Z6Z0kij/qNTeTTWFd5yawX +2DP2+6EP +-----END CERTIFICATE REQUEST----- \ No newline at end of file diff --git a/x509util/testdata/rawSubject.key b/x509util/testdata/rawSubject.key new file mode 100644 index 00000000..768c3067 --- /dev/null +++ b/x509util/testdata/rawSubject.key @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIK9FBgwqr6Zjsbf2uPmvnDz341AhiJbPLTuq8+/BLbd/oAoGCCqGSM49 +AwEHoUQDQgAExjS2bc7+XXJdjc+ulwVfrauYygh/Vhj5bLgRKuPDTVG9S83nI2lU +2bBMHvmaUG585ME3WFxSOvB26L8VnPXw8Q== +-----END EC PRIVATE KEY----- diff --git a/x509util/testdata/rawSubject.tpl b/x509util/testdata/rawSubject.tpl new file mode 100644 index 00000000..d87f5b2c --- /dev/null +++ b/x509util/testdata/rawSubject.tpl @@ -0,0 +1,10 @@ +{ + "rawSubject": {{ toJson .Insecure.CR.RawSubject }}, + "sans": {{ toJson .SANs }}, +{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }} + "keyUsage": ["keyEncipherment", "digitalSignature"], +{{- else }} + "keyUsage": ["digitalSignature"], +{{- end }} + "extKeyUsage": ["serverAuth", "clientAuth"] +} \ No newline at end of file