certdataDiffCCADB/utils/entry.go (58 lines of code) (raw):
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package utils
import (
"fmt"
"regexp"
"strings"
)
// Certificate normalization constants.
const (
BEGIN = "-----BEGIN CERTIFICATE-----\n"
END = "-----END CERTIFICATE-----"
WIDTH = 64 // Columns per line https://tools.ietf.org/html/rfc1421
)
var stripper *regexp.Regexp
func init() {
stripper = regexp.MustCompile("('|'|\n|-----BEGIN CERTIFICATE-----|-----END CERTIFICATE-----)")
}
// Entry is a normalized form of a Certificate Authority found
// in either certdata.txt or from a CCADB report CSV.
type Entry struct {
OrganizationName string `json:"organizationName"`
OrganizationalUnitName string `json:"organizationalUnitName"`
CommonName string `json:"commonName"`
SerialNumber string `json:"serialNumber"`
PEM string `json:"-"`
Fingerprint string `json:"sha256"`
TrustWeb bool `json:"trustWeb"`
TrustEmail bool `json:"trustEmail"`
LineNumber int `json:"lineNumber"`
Origin string `json:"origin"`
}
// UniqueID returns the issuer distinguished name and the serial (noralized with no leading zeroes)
// contatenated together.
func (e *Entry) UniqueID() string {
return fmt.Sprintf("%v%v", e.DistinguishedName(), e.NormalizedSerial())
}
// DistinguishedName builds a hierarchical string of Organization, Orgizational Unit, and Common Name.
func (e *Entry) DistinguishedName() string {
return fmt.Sprintf("O=%v/OU=%v/CN=%v", e.OrganizationName, e.OrganizationalUnitName, e.CommonName)
}
// NormalizedSerial returns the serial number with any leading zeroes stripped off.
func (e *Entry) NormalizedSerial() string {
return strings.TrimLeft(e.SerialNumber, "0")
}
// NewEntry constructs a new Entry with a normalized PEM.
func NewEntry(org, orgUnit, commonName, serial, pem, fingerprint string, trustWeb, trustEmail bool, line int, origin string) *Entry {
return &Entry{org, orgUnit, commonName, serial, NormalizePEM(pem), fingerprint, trustWeb, trustEmail, line, origin}
}
// normalizePEM ignores any formatting or string artifacts that the PEM may have had
// and applies https://tools.ietf.org/html/rfc1421
//
// This stemmed from noticing that CCADB reports were fully formed while certdata
// PEMS had no formatting nor BEGIN/END fields. This is simply avoiding any surprises
// in individual formatting choices by forcing both to strip all formatting and conform
// to the one, chosen, way.
func NormalizePEM(pem string) string {
if len(pem) == 0 {
return ""
}
pem = stripper.ReplaceAllString(pem, "")
p := []byte(pem)
fmted := []byte(BEGIN)
width := WIDTH
for len(p) > 0 {
if len(p) < WIDTH {
width = len(p)
}
fmted = append(fmted, p[:width]...)
fmted = append(fmted, '\n')
p = p[width:]
}
fmted = append(fmted, END...)
return string(fmted)
}