From 37f230a506031fb89dd06a1bad22d343cd8ded15 Mon Sep 17 00:00:00 2001 From: Vincent Janelle Date: Sat, 20 Apr 2019 14:31:57 -0700 Subject: [PATCH] (#34) Validate email addresses in SANs SAN fields can contain email addresses, and the default X509 Verify doesn't include these. Loop through until we find a match, return an error otherwise. --- filesec/file_security.go | 15 +++++++- filesec/file_security_test.go | 34 +++++++++++++++++++ testdata/intermediate/Makefile | 7 ++++ .../certs/email-chain-rip.mcollective.pem | 34 +++++++++++++++++++ testdata/intermediate/email.json | 11 ++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 testdata/intermediate/certs/email-chain-rip.mcollective.pem create mode 100644 testdata/intermediate/email.json diff --git a/filesec/file_security.go b/filesec/file_security.go index b3e1418..262a955 100644 --- a/filesec/file_security.go +++ b/filesec/file_security.go @@ -442,7 +442,9 @@ func (s *FileSecurity) VerifyCertificate(certpem []byte, name string) error { KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, } - if name != "" { + // If there is an email address in the name passed, we should not search by DNSName + // in the CN or SAN + if name != "" && !strings.HasPrefix(name, "email:") { opts.DNSName = name } @@ -452,6 +454,17 @@ func (s *FileSecurity) VerifyCertificate(certpem []byte, name string) error { return err } + if len(cert.EmailAddresses) > 0 && strings.HasPrefix(name, "email:") { + s.log.Debug("Email addresses found in certificate, attempting verification") + for _, email := range cert.EmailAddresses { + if strings.TrimPrefix(name, "email:") == email { + return nil + } + } + + return fmt.Errorf("email address not found in SAN: %s, %v", name, cert.EmailAddresses) + } + return nil } diff --git a/filesec/file_security_test.go b/filesec/file_security_test.go index 3bdedb9..9d855c3 100644 --- a/filesec/file_security_test.go +++ b/filesec/file_security_test.go @@ -404,6 +404,40 @@ var _ = Describe("FileSSL", func() { err = prov.VerifyCertificate(pem, "rip.mcollective") Expect(err).ToNot(HaveOccurred()) }) + + It("Should work with email addresses", func() { + c, err := config.NewDefaultConfig() + Expect(err).ToNot(HaveOccurred()) + + c.Choria.FileSecurityCA = filepath.Join("..", "testdata", "intermediate", "certs", "ca_chain_ca.pem") + c.Choria.FileSecurityCache = filepath.Join("..", "testdata", "intermediate", "certs") + + prov, err := New(WithChoriaConfig(c), WithLog(l.WithFields(logrus.Fields{}))) + Expect(err).ToNot(HaveOccurred()) + + pem, err = ioutil.ReadFile(filepath.Join("..", "testdata", "intermediate", "certs", "email-chain-rip.mcollective.pem")) + Expect(err).ToNot(HaveOccurred()) + + err = prov.VerifyCertificate(pem, "email:test@choria-io.com") + Expect(err).ToNot(HaveOccurred()) + }) + + It("Should not work with wrong addresses", func() { + c, err := config.NewDefaultConfig() + Expect(err).ToNot(HaveOccurred()) + + c.Choria.FileSecurityCA = filepath.Join("..", "testdata", "intermediate", "certs", "ca_chain_ca.pem") + c.Choria.FileSecurityCache = filepath.Join("..", "testdata", "intermediate", "certs") + + prov, err := New(WithChoriaConfig(c), WithLog(l.WithFields(logrus.Fields{}))) + Expect(err).ToNot(HaveOccurred()) + + pem, err = ioutil.ReadFile(filepath.Join("..", "testdata", "intermediate", "certs", "email-chain-rip.mcollective.pem")) + Expect(err).ToNot(HaveOccurred()) + + err = prov.VerifyCertificate(pem, "email:bad@choria-io.com") + Expect(err).To(HaveOccurred()) + }) }) Describe("PublicCertPem", func() { diff --git a/testdata/intermediate/Makefile b/testdata/intermediate/Makefile index 980eb7f..a7dcd32 100644 --- a/testdata/intermediate/Makefile +++ b/testdata/intermediate/Makefile @@ -24,6 +24,13 @@ ca_chain: cat rip.mcollective.pem > certs/ca_chain_rip.mcollective.pem openssl verify -CAfile certs/ca_chain_ca.pem certs/ca_chain_rip.mcollective.pem +email: + cfssl genkey email.json | cfssljson -bare email.rip.mcollective + cfssl gencsr -key email.rip.mcollective-key.pem email.json | cfssljson -bare email.rip.mcollective + cfssl sign -ca intermediate.pem -ca-key intermediate-key.pem email.rip.mcollective.csr subject.json | cfssljson -bare email.rip.mcollective && openssl x509 -in email.rip.mcollective.pem -noout -text + cat email.rip.mcollective.pem intermediate.pem > email-chain-rip.mcollective.pem + openssl verify -CAfile ca.pem -untrusted email-chain-rip.mcollective.pem email-chain-rip.mcollective.pem + cp email-chain-rip.mcollective.pem certs/email-chain-rip.mcollective.pem deploy: cp ca.pem certs/ca.pem diff --git a/testdata/intermediate/certs/email-chain-rip.mcollective.pem b/testdata/intermediate/certs/email-chain-rip.mcollective.pem new file mode 100644 index 0000000..46436c2 --- /dev/null +++ b/testdata/intermediate/certs/email-chain-rip.mcollective.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIDGjCCAsCgAwIBAgIUMo6d0nZxDYqzLqmadFKA3CVePzMwCgYIKoZIzj0EAwIw +gYExCzAJBgNVBAYTAlhYMREwDwYDVQQIEwhMb2NhbGl0eTENMAsGA1UEBxMEQ2l0 +eTEPMA0GA1UEChMGQ2hvcmlhMSUwIwYDVQQLExxVbml0IHRlc3RpbmcgSW50ZXJt +ZWRpYXRlIENBMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0EwHhcNMTkwNDIwMjA0 +OTAwWhcNMjAwNDE5MjA0OTAwWjAaMRgwFgYDVQQDEw9yaXAubWNvbGxlY3RpdmUw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtsM3QOOd4NrtvzWf2ZJMK +NunT54NcjKp7Etz0bG3uz4XJAVzAvTjCgbTjDU7ggsG0h2SWrJpZfOisBZ6AolUS +29Plkq/Lgsh7f6iLNWlXSOlyWj15PKp3pC8KzX1tOeGB4xkR3Khr2EzUOLIRpmTw +QOD/vGs8hv71qkTl5NXCOWaaNHyr6gqZR6bqQaxk6eg+gnxMPz6ztHEWfv+rpaTL +nCdgMVs5YNYfyWeiJWojSqjqFqevuoqc3krfM173Ep+5b9VAaj/zEOSEjvSP9Vlp +QWhhZVkdlTQI51tqj4N1LOVgzLk3CdcOhwoO8f2FDHbaRWg0zDqU8pacUGpCzE77 +AgMBAAGjgbAwga0wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB +BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRJS6Jh8RgvIjUGCqYV +FU4GjbFnqTAfBgNVHSMEGDAWgBSlQrdE6JCCk8azRsWXnRuk2ctF+jAuBgNVHREE +JzAlgg9yaXAubWNvbGxlY3RpdmWBEnRlc3RAY2hvcmlhLWlvLmNvbTAKBggqhkjO +PQQDAgNIADBFAiATwlrjYLSsuck/jR0HwmDqz0kZQrS376eznSTn1pcSHgIhAMto +kdnFfpLcIdAHZ4tprfJkOSkkJjf+ei+FlCi1EmOR +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICZDCCAgmgAwIBAgIUMHE90peOTHN6Iv2S2R2astND6lswCgYIKoZIzj0EAwIw +eTELMAkGA1UEBhMCWFgxETAPBgNVBAgTCExvY2FsaXR5MQ0wCwYDVQQHEwRDaXR5 +MQ8wDQYDVQQKEwZDaG9yaWExJTAjBgNVBAsTHFVuaXQgdGVzdGluZyBJbnRlcm1l +ZGlhdGUgQ0ExEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTgxMTEzMDEyMzAwWhcNNDgx +MTA1MDEyMzAwWjCBgTELMAkGA1UEBhMCWFgxETAPBgNVBAgTCExvY2FsaXR5MQ0w +CwYDVQQHEwRDaXR5MQ8wDQYDVQQKEwZDaG9yaWExJTAjBgNVBAsTHFVuaXQgdGVz +dGluZyBJbnRlcm1lZGlhdGUgQ0ExGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTBZ +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABNGtHy1coQANdtEj/OK8JjgVxQ+owXlq +X3PWtohIhx1dlD4MS78sPoEblHcU5NAfSPTN23gPw2kalFjV5NJH3I+jZjBkMA4G +A1UdDwEB/wQEAwIBpjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSlQrdE +6JCCk8azRsWXnRuk2ctF+jAfBgNVHSMEGDAWgBQ2M6o4bz7r8MgG9Q0/7rN8Ogoi +ETAKBggqhkjOPQQDAgNJADBGAiEAueRTGMy56l9024iI0tE+huS5E0wEu1ZyQfpI +AnqVQ70CIQCqVCe23uL3Po9THrXrmpVF7n+CJLQnKdpM3uxxsPWAIg== +-----END CERTIFICATE----- diff --git a/testdata/intermediate/email.json b/testdata/intermediate/email.json new file mode 100644 index 0000000..ae0351d --- /dev/null +++ b/testdata/intermediate/email.json @@ -0,0 +1,11 @@ +{ + "hosts": [ + "rip.mcollective", + "test@choria-io.com" + ], + "key": { + "algo": "rsa", + "size": 2048 + }, + "names": [ ] +}