diff --git a/cmd/ctparsewatch/main.go b/cmd/ctparsewatch/main.go index bd180c1..82edfa8 100644 --- a/cmd/ctparsewatch/main.go +++ b/cmd/ctparsewatch/main.go @@ -28,6 +28,9 @@ func processEntry (scanner *ctwatch.Scanner, entry *ct.LogEntry) { } info.CertInfo, info.ParseError = ctwatch.MakeCertInfoFromLogEntry(entry) + if info.CertInfo != nil { + info.Identifiers, info.IdentifiersParseError = info.CertInfo.ParseIdentifiers() + } if info.HasParseErrors() { cmd.LogEntry(&info) diff --git a/cmd/ctwatch/main.go b/cmd/ctwatch/main.go index e669e69..dbfe536 100644 --- a/cmd/ctwatch/main.go +++ b/cmd/ctwatch/main.go @@ -104,12 +104,15 @@ func processEntry (scanner *ctwatch.Scanner, entry *ct.LogEntry) { info.CertInfo, info.ParseError = ctwatch.MakeCertInfoFromLogEntry(entry) - // If there's any sort of parse error related to the identifiers, report - // the certificate because we can't say for sure it doesn't match a domain - // we care about (fail safe behavior). - if info.ParseError != nil || - info.CertInfo.IdentifiersParseError != nil || - anyDnsNameMatches(info.CertInfo.Identifiers.DNSNames) { + if info.CertInfo != nil { + info.Identifiers, info.IdentifiersParseError = info.CertInfo.ParseIdentifiers() + } + + // Fail safe behavior: if info.Identifiers is nil (which is caused by a + // parse error), report the certificate because we can't say for sure it + // doesn't match a domain we care about. We try very hard to make sure + // parsing identifiers always succeeds, so false alarms should be rare. + if info.Identifiers == nil || anyDnsNameMatches(info.Identifiers.DNSNames) { cmd.LogEntry(&info) } } diff --git a/helpers.go b/helpers.go index fc72650..6ef08b8 100644 --- a/helpers.go +++ b/helpers.go @@ -96,14 +96,14 @@ type EntryInfo struct { FullChain [][]byte // first entry is logged X509 cert or pre-cert CertInfo *CertInfo ParseError error // set iff CertInfo is nil + Identifiers *Identifiers + IdentifiersParseError error Filename string } type CertInfo struct { TBS *TBSCertificate - Identifiers *Identifiers - IdentifiersParseError error Subject RDNSequence SubjectParseError error Issuer RDNSequence @@ -121,7 +121,6 @@ type CertInfo struct { func MakeCertInfoFromTBS (tbs *TBSCertificate) *CertInfo { info := &CertInfo{TBS: tbs} - info.Identifiers, info.IdentifiersParseError = tbs.ParseIdentifiers() info.Subject, info.SubjectParseError = tbs.ParseSubject() info.Issuer, info.IssuerParseError = tbs.ParseIssuer() info.SANs, info.SANsParseError = tbs.ParseSubjectAltNames() @@ -161,29 +160,6 @@ func MakeCertInfoFromLogEntry (entry *ct.LogEntry) (*CertInfo, error) { } } -func (info *CertInfo) dnsNamesString (sep string) string { - if info.IdentifiersParseError == nil { - return strings.Join(info.Identifiers.DNSNames, sep) - } else { - return "" - } -} - -func (info *CertInfo) ipAddrsString (sep string) string { - if info.IdentifiersParseError == nil { - str := "" - for _, ipAddr := range info.Identifiers.IPAddrs { - if str != "" { - str += sep - } - str += ipAddr.String() - } - return str - } else { - return "" - } -} - func (info *CertInfo) NotBefore () *time.Time { if info.ValidityParseError == nil { return &info.Validity.NotBefore @@ -213,13 +189,6 @@ func (info *CertInfo) Environ () []string { env = append(env, "PUBKEY_HASH=" + info.PubkeyHash()) - if info.IdentifiersParseError != nil { - env = append(env, "IDENTIFIERS_PARSE_ERROR=" + info.IdentifiersParseError.Error()) - } else { - env = append(env, "DNS_NAMES=" + info.dnsNamesString(",")) - env = append(env, "IP_ADDRESSES=" + info.ipAddrsString(",")) - } - if info.SerialNumberParseError != nil { env = append(env, "SERIAL_PARSE_ERROR=" + info.SerialNumberParseError.Error()) } else { @@ -254,7 +223,7 @@ func (info *CertInfo) Environ () []string { func (info *EntryInfo) HasParseErrors () bool { return info.ParseError != nil || - info.CertInfo.IdentifiersParseError != nil || + info.IdentifiersParseError != nil || info.CertInfo.SubjectParseError != nil || info.CertInfo.IssuerParseError != nil || info.CertInfo.SANsParseError != nil || @@ -315,11 +284,17 @@ func (info *EntryInfo) Environ () []string { if info.Filename != "" { env = append(env, "CERT_FILENAME=" + info.Filename) } - if info.ParseError == nil { + if info.ParseError != nil { + env = append(env, "PARSE_ERROR=" + info.ParseError.Error()) + } else if info.CertInfo != nil { certEnv := info.CertInfo.Environ() env = append(env, certEnv...) - } else { - env = append(env, "PARSE_ERROR=" + info.ParseError.Error()) + } + if info.IdentifiersParseError != nil { + env = append(env, "IDENTIFIERS_PARSE_ERROR=" + info.IdentifiersParseError.Error()) + } else if info.Identifiers != nil { + env = append(env, "DNS_NAMES=" + info.Identifiers.dnsNamesString(",")) + env = append(env, "IP_ADDRESSES=" + info.Identifiers.ipAddrsString(",")) } return env @@ -336,19 +311,19 @@ func writeField (out io.Writer, name string, value interface{}, err error) { func (info *EntryInfo) Write (out io.Writer) { fingerprint := info.Fingerprint() fmt.Fprintf(out, "%s:\n", fingerprint) + if info.IdentifiersParseError != nil { + writeField(out, "Identifiers", nil, info.IdentifiersParseError) + } else if info.Identifiers != nil { + for _, dnsName := range info.Identifiers.DNSNames { + writeField(out, "DNS Name", dnsName, nil) + } + for _, ipaddr := range info.Identifiers.IPAddrs { + writeField(out, "IP Address", ipaddr, nil) + } + } if info.ParseError != nil { writeField(out, "Parse Error", "*** " + info.ParseError.Error() + " ***", nil) - } else { - if info.CertInfo.IdentifiersParseError != nil { - writeField(out, "Identifiers", nil, info.CertInfo.IdentifiersParseError) - } else { - for _, dnsName := range info.CertInfo.Identifiers.DNSNames { - writeField(out, "DNS Name", dnsName, nil) - } - for _, ipaddr := range info.CertInfo.Identifiers.IPAddrs { - writeField(out, "IP Address", ipaddr, nil) - } - } + } else if info.CertInfo != nil { writeField(out, "Pubkey", info.CertInfo.PubkeyHash(), nil) writeField(out, "Subject", info.CertInfo.Subject, info.CertInfo.SubjectParseError) if info.CertInfo.SANsParseError != nil { diff --git a/identifiers.go b/identifiers.go index c9acc0b..b19d14f 100644 --- a/identifiers.go +++ b/identifiers.go @@ -232,10 +232,28 @@ func (ids *Identifiers) AddIPAddress (value net.IP) { ids.IPAddrs = append(ids.IPAddrs, value) } -func (tbs *TBSCertificate) ParseIdentifiers () (*Identifiers, error) { +func (ids *Identifiers) dnsNamesString (sep string) string { + return strings.Join(ids.DNSNames, sep) +} + +func (ids *Identifiers) ipAddrsString (sep string) string { + str := "" + for _, ipAddr := range ids.IPAddrs { + if str != "" { + str += sep + } + str += ipAddr.String() + } + return str +} + +func (cert *CertInfo) ParseIdentifiers () (*Identifiers, error) { ids := NewIdentifiers() - cns, err := tbs.ParseSubjectCommonNames() + if cert.SubjectParseError != nil { + return nil, cert.SubjectParseError + } + cns, err := cert.Subject.ParseCNs() if err != nil { return nil, err } @@ -243,11 +261,10 @@ func (tbs *TBSCertificate) ParseIdentifiers () (*Identifiers, error) { ids.AddCN(cn) } - sans, err := tbs.ParseSubjectAltNames() - if err != nil { - return nil, err + if cert.SANsParseError != nil { + return nil, cert.SANsParseError } - for _, san := range sans { + for _, san := range cert.SANs { switch san.Type { case sanDNSName: ids.AddDnsSAN(san.Value)