mirror of https://github.com/namecoin/ncdns
ncdumpzone: Add Firefox mode.
This mode outputs a cert_override.txt file (based on TLSA records) that Firefox will accept.pull/61/head
parent
3792dd3e95
commit
2e50c75232
@ -0,0 +1,124 @@
|
||||
package tlsoverridefirefox
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/namecoin/ncdns/util"
|
||||
)
|
||||
|
||||
// OverrideFromRR returns a Firefox certificate override (in cert_override.txt
|
||||
// format) derived from rr. If no such override can be derived, returns an
|
||||
// empty string.
|
||||
func OverrideFromRR(rr dns.RR) (string, error) {
|
||||
tlsa, ok := rr.(*dns.TLSA)
|
||||
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
portLabel, protocolLabelAndHost := util.SplitDomainTail(tlsa.Hdr.Name)
|
||||
protocolLabel, hostFQDN := util.SplitDomainTail(protocolLabelAndHost)
|
||||
|
||||
if protocolLabel != "_tcp" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(portLabel, "_") {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
port := strings.TrimPrefix(portLabel, "_")
|
||||
|
||||
if !strings.HasSuffix(hostFQDN, ".") {
|
||||
return "", fmt.Errorf("TLSA not a FQDN")
|
||||
}
|
||||
|
||||
host := strings.TrimSuffix(hostFQDN, ".")
|
||||
|
||||
// SHA256, as per https://dxr.mozilla.org/mozilla-central/source/security/manager/ssl/nsCertOverrideService.cpp
|
||||
fingerprintAlgo := "OID.2.16.840.1.101.3.4.2.1"
|
||||
|
||||
// Possible Usage values:
|
||||
// 0: CA constraint. No override is necessary.
|
||||
// 1: Service certificate constraint. No override is necessary.
|
||||
// 2: Trust anchor assertion. Firefox doesn't support these.
|
||||
// 3: Domain-issued certificate. Do an override in this case.
|
||||
|
||||
if tlsa.Usage != 3 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Only a full certificate selector can yield a SHA256 certificate
|
||||
// fingerprint.
|
||||
if tlsa.Selector != 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
fingerprint, err := getFingerprint(tlsa)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
overrideMask := "U"
|
||||
|
||||
// Format documented in https://dxr.mozilla.org/mozilla-central/source/security/manager/ssl/nsNSSCertificate.cpp
|
||||
// However, it looks empirically like we can just use 0-length serial
|
||||
// number and 0-length DN, and Firefox doesn't care.
|
||||
dbKey := base64.StdEncoding.EncodeToString([]byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||
|
||||
return host + ":" + port + "\t" + fingerprintAlgo + "\t" +
|
||||
fingerprint + "\t" + overrideMask + "\t" + dbKey + "\n", nil
|
||||
}
|
||||
|
||||
func getFingerprint(tlsa *dns.TLSA) (string, error) {
|
||||
var fingerprint string
|
||||
|
||||
// SHA512 fingerprint can't yield a SHA256 fingerprint
|
||||
if tlsa.MatchingType == 2 {
|
||||
return "", fmt.Errorf("SHA512 fingerprint can't yield a " +
|
||||
"SHA256 fingerprint")
|
||||
}
|
||||
|
||||
if tlsa.MatchingType == 1 {
|
||||
// SHA256 fingerprint
|
||||
|
||||
fingerprintBytes, err := hex.DecodeString(tlsa.Certificate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fingerprint = insertColons(fingerprintBytes)
|
||||
} else if tlsa.MatchingType == 0 {
|
||||
// Exact match
|
||||
|
||||
certificateBytes, err := hex.DecodeString(tlsa.Certificate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fingerprintArray := sha256.Sum256(certificateBytes)
|
||||
|
||||
fingerprint = insertColons(fingerprintArray[:])
|
||||
} else {
|
||||
// Unknown MatchingType
|
||||
return "", fmt.Errorf("Unknown MatchingType")
|
||||
}
|
||||
|
||||
return strings.ToUpper(fingerprint), nil
|
||||
}
|
||||
|
||||
// Based on FingerprintLegacyMD5 from
|
||||
// https://github.com/golang/crypto/blob/master/ssh/keys.go
|
||||
func insertColons(input []byte) string {
|
||||
hexarray := make([]string, len(input))
|
||||
for i, c := range input {
|
||||
hexarray[i] = hex.EncodeToString([]byte{c})
|
||||
}
|
||||
return strings.Join(hexarray, ":")
|
||||
}
|
Loading…
Reference in New Issue