Save malformed entries, and put paths in environment variables
To allow scripts to access them.
This commit is contained in:
parent
ee8ae0c1f3
commit
bd2bab5fcb
|
@ -138,6 +138,14 @@ The following environment variables are set for `malformed_cert` events:
|
||||||
|
|
||||||
: A human-readable string describing why the certificate is malformed.
|
: A human-readable string describing why the certificate is malformed.
|
||||||
|
|
||||||
|
`ENTRY_FILENAME`
|
||||||
|
|
||||||
|
: Path to a file containing the JSON log entry. The file contains a JSON object with two fields, `leaf_input` and `extra_data`, as described in RFC 6962 Section 4.6.
|
||||||
|
|
||||||
|
`TEXT_FILENAME`
|
||||||
|
|
||||||
|
: Path to a file containing a text message describing the malformed certificate. This file contains the same text that certspotter uses in emails.
|
||||||
|
|
||||||
# JSON FILE FORMAT
|
# JSON FILE FORMAT
|
||||||
|
|
||||||
Unless `-no_save` is used, certspotter saves a JSON file for every discovered certificate
|
Unless `-no_save` is used, certspotter saves a JSON file for every discovered certificate
|
||||||
|
|
|
@ -17,6 +17,28 @@ import (
|
||||||
type malformedLogEntry struct {
|
type malformedLogEntry struct {
|
||||||
Entry *logEntry
|
Entry *logEntry
|
||||||
Error string
|
Error string
|
||||||
|
EntryPath string
|
||||||
|
TextPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (malformed *malformedLogEntry) entryJSON() any {
|
||||||
|
return struct {
|
||||||
|
LeafInput []byte `json:"leaf_input"`
|
||||||
|
ExtraData []byte `json:"extra_data"`
|
||||||
|
}{
|
||||||
|
LeafInput: malformed.Entry.LeafInput,
|
||||||
|
ExtraData: malformed.Entry.ExtraData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (malformed *malformedLogEntry) save() error {
|
||||||
|
if err := writeJSONFile(malformed.EntryPath, malformed.entryJSON(), 0666); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeTextFile(malformed.TextPath, malformed.Text(), 0666); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (malformed *malformedLogEntry) Environ() []string {
|
func (malformed *malformedLogEntry) Environ() []string {
|
||||||
|
@ -27,6 +49,8 @@ func (malformed *malformedLogEntry) Environ() []string {
|
||||||
"ENTRY_INDEX=" + fmt.Sprint(malformed.Entry.Index),
|
"ENTRY_INDEX=" + fmt.Sprint(malformed.Entry.Index),
|
||||||
"LEAF_HASH=" + malformed.Entry.LeafHash.Base64String(),
|
"LEAF_HASH=" + malformed.Entry.LeafHash.Base64String(),
|
||||||
"PARSE_ERROR=" + malformed.Error,
|
"PARSE_ERROR=" + malformed.Error,
|
||||||
|
"ENTRY_FILENAME=" + malformed.EntryPath,
|
||||||
|
"TEXT_FILENAME=" + malformed.TextPath,
|
||||||
"CERT_PARSEABLE=no", // backwards compat with pre-0.15.0; not documented
|
"CERT_PARSEABLE=no", // backwards compat with pre-0.15.0; not documented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,8 +77,9 @@ func monitorLog(ctx context.Context, config *Config, ctlog *loglist.Log, logClie
|
||||||
stateDirPath = filepath.Join(config.StateDir, "logs", ctlog.LogID.Base64URLString())
|
stateDirPath = filepath.Join(config.StateDir, "logs", ctlog.LogID.Base64URLString())
|
||||||
stateFilePath = filepath.Join(stateDirPath, "state.json")
|
stateFilePath = filepath.Join(stateDirPath, "state.json")
|
||||||
sthsDirPath = filepath.Join(stateDirPath, "unverified_sths")
|
sthsDirPath = filepath.Join(stateDirPath, "unverified_sths")
|
||||||
|
malformedDirPath = filepath.Join(stateDirPath, "malformed_entries")
|
||||||
)
|
)
|
||||||
for _, dirPath := range []string{stateDirPath, sthsDirPath} {
|
for _, dirPath := range []string{stateDirPath, sthsDirPath, malformedDirPath} {
|
||||||
if err := os.Mkdir(dirPath, 0777); err != nil && !errors.Is(err, fs.ErrExist) {
|
if err := os.Mkdir(dirPath, 0777); err != nil && !errors.Is(err, fs.ErrExist) {
|
||||||
return fmt.Errorf("error creating state directory: %w", err)
|
return fmt.Errorf("error creating state directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,12 +157,18 @@ func processCertificate(ctx context.Context, config *Config, entry *logEntry, ce
|
||||||
}
|
}
|
||||||
|
|
||||||
func processMalformedLogEntry(ctx context.Context, config *Config, entry *logEntry, parseError error) error {
|
func processMalformedLogEntry(ctx context.Context, config *Config, entry *logEntry, parseError error) error {
|
||||||
// TODO-4: save the malformed entry (in get-entries format) in the state directory so user can inspect it
|
dirPath := filepath.Join(config.StateDir, "logs", entry.Log.LogID.Base64URLString(), "malformed_entries")
|
||||||
|
|
||||||
malformed := &malformedLogEntry{
|
malformed := &malformedLogEntry{
|
||||||
Entry: entry,
|
Entry: entry,
|
||||||
Error: parseError.Error(),
|
Error: parseError.Error(),
|
||||||
|
EntryPath: filepath.Join(dirPath, fmt.Sprintf("%d.json", entry.Index)),
|
||||||
|
TextPath: filepath.Join(dirPath, fmt.Sprintf("%d.txt", entry.Index)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := malformed.save(); err != nil {
|
||||||
|
return fmt.Errorf("error saving malformed log entry %d in %s (%q): %w", entry.Index, entry.Log.URL, parseError, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := notify(ctx, config, malformed); err != nil {
|
if err := notify(ctx, config, malformed); err != nil {
|
||||||
return fmt.Errorf("error notifying about malformed log entry %d in %s (%q): %w", entry.Index, entry.Log.URL, parseError, err)
|
return fmt.Errorf("error notifying about malformed log entry %d in %s (%q): %w", entry.Index, entry.Log.URL, parseError, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue