mirror of https://github.com/namecoin/ncdns
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.8 KiB
Go
127 lines
3.8 KiB
Go
package tlshook
|
|
|
|
import (
|
|
"github.com/namecoin/ncdns/certdehydrate"
|
|
"github.com/namecoin/ncdns/certinject"
|
|
"github.com/namecoin/ncdns/ncdomain"
|
|
"github.com/namecoin/ncdns/x509"
|
|
"github.com/hlandau/xlog"
|
|
)
|
|
|
|
import "bytes"
|
|
import "encoding/hex"
|
|
|
|
var log, Log = xlog.New("ncdns.tlshook")
|
|
|
|
func DomainValueHookTLS(qname string, ncv *ncdomain.Value) (err error) {
|
|
|
|
log.Info("Intercepted a Value for ", qname)
|
|
if protocol, ok := ncv.Map["_tcp"]; ok { // TODO: look into allowing non-TCP protocols
|
|
log.Info("Saw a request with TCP")
|
|
if port, ok := protocol.Map["_443"]; ok { // TODO: check all ports, not just 443
|
|
log.Info("Saw a request with TCP port 443")
|
|
|
|
|
|
// For dehydrated certificates
|
|
if len(port.TLSAGenerated) > 0 {
|
|
|
|
log.Info("Just saw a TLS port 443 capable domain request for ", qname, "!")
|
|
|
|
for index, cert := range port.TLSAGenerated {
|
|
|
|
log.Info("Using dehydrated certificate # ", index)
|
|
|
|
template := cert
|
|
|
|
derBytes, err := certdehydrate.FillRehydratedCertTemplate(template, qname)
|
|
if err != nil {
|
|
log.Info("Failed to create certificate: ", err)
|
|
continue
|
|
}
|
|
|
|
// TODO: check return value
|
|
certinject.InjectCert(derBytes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// For non-dehydrated certificates
|
|
// TODO: test this code.
|
|
// since this code has not been tested yet, it's disabled for safety reasons.
|
|
//if len(port.TLSA) > 0 {
|
|
if false {
|
|
|
|
log.Info("Just saw a TLS port 443 capable domain request for ", qname, "!")
|
|
|
|
for index, cert := range port.TLSA {
|
|
|
|
// cert usage 3 is end-entity cert that need not pass CA-based validation
|
|
// cert selector 0 is a full certificate (not just public key)
|
|
// cert matching type 0 is exact match (not hashed)
|
|
if cert.Usage == 3 && cert.Selector == 0 && cert.MatchingType == 0 {
|
|
|
|
log.Info("Certificate # ", index, " is usable with hex value ", cert.Certificate)
|
|
|
|
origCertBytes, err:= hex.DecodeString(cert.Certificate)
|
|
if err != nil {
|
|
log.Info("Failed to decode hex string of TLSA certificate, ", err)
|
|
continue
|
|
}
|
|
|
|
origCert, err := x509.ParseCertificate(origCertBytes)
|
|
if err != nil {
|
|
log.Info("Failed to parse TLSA certificate, ", err)
|
|
continue
|
|
}
|
|
|
|
// TODO: look into being a bit more flexible with cert serial number, validity period, and subject serial number.
|
|
// The uniformity in those fields is due to compression rather than security concerns.
|
|
// So we could possibly pass those through in cases like this.
|
|
// Subject serial number is also there due to transparency concerns, so maybe don't allow customizing it.
|
|
|
|
dehydrated, err := certdehydrate.DehydrateCert(origCert)
|
|
if err != nil {
|
|
log.Info("Failed to dehydrate TLSA certificate, ", err)
|
|
continue
|
|
}
|
|
|
|
rehydrated, err := certdehydrate.RehydrateCert(dehydrated)
|
|
if err != nil {
|
|
log.Info("Failed to rehydrate TLSA certificate, ", err)
|
|
continue
|
|
}
|
|
|
|
rehydratedDerBytes, err := certdehydrate.FillRehydratedCertTemplate(*rehydrated, qname)
|
|
if err != nil {
|
|
log.Info("Failed to fill rehydrated TLSA certificate, ", err)
|
|
continue
|
|
}
|
|
|
|
if ! bytes.Equal(origCertBytes, rehydratedDerBytes) {
|
|
log.Info("TLSA certificate didn't conform to dehydration template; skipping certificate.")
|
|
continue
|
|
}
|
|
|
|
// TODO: check return value
|
|
certinject.InjectCert(rehydratedDerBytes)
|
|
|
|
} else {
|
|
|
|
log.Info("Certificate # ", index, " is not usable because we cannot recover the full end-entity certificate from the TLSA record.")
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove any certs that aren't valid anymore
|
|
certinject.CleanCerts()
|
|
|
|
err = nil
|
|
|
|
return
|
|
|
|
} |