-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add parameter to the resolver's LookupIP method to exclude non authen…
…ticated responses. Switch to goproxy it's lightweight, appears to be more maintained, and doesn't break web sockets. Avoid doing TLSA lookups if no authenticated IP addresses are available. Send the authenticated response via proxy context to dialTLS in HTTP transport. Move proxy details to proxy.go and use the cmd app only to configure and start godane. Encrypt the private key
- Loading branch information
Showing
11 changed files
with
698 additions
and
359 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
|
||
type entry struct { | ||
msg []dns.RR | ||
ad bool | ||
ttl time.Time | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
package godane | ||
|
||
// adopted from github.com/google/martian/mitm | ||
// modified to use with godane and to make it work with goproxy | ||
|
||
import ( | ||
"bytes" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/sha1" | ||
"crypto/tls" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"fmt" | ||
"log" | ||
"math/big" | ||
"net" | ||
"sync" | ||
"time" | ||
) | ||
|
||
// maxSerialNumber is the upper boundary that is used to create unique serial | ||
// numbers for the certificate. This can be any unsigned integer up to 20 | ||
// bytes (2^(8*20)-1). | ||
var maxSerialNumber = big.NewInt(0).SetBytes(bytes.Repeat([]byte{255}, 20)) | ||
|
||
// mitmConfig is a set of configuration values that are used to build TLS configs | ||
// capable of MITM. | ||
type mitmConfig struct { | ||
ca *x509.Certificate | ||
capriv interface{} | ||
priv *rsa.PrivateKey | ||
keyID []byte | ||
validity time.Duration | ||
org string | ||
getCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) | ||
roots *x509.CertPool | ||
|
||
certmu sync.RWMutex | ||
certs map[string]*tls.Certificate | ||
} | ||
|
||
// NewAuthority creates a new CA certificate and associated | ||
// private key. | ||
func NewAuthority(name, organization string, validity time.Duration) (*x509.Certificate, *rsa.PrivateKey, error) { | ||
priv, err := rsa.GenerateKey(rand.Reader, 2048) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
pub := priv.Public() | ||
|
||
// Subject Key Identifier support for end entity certificate. | ||
// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2) | ||
pkixpub, err := x509.MarshalPKIXPublicKey(pub) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
h := sha1.New() | ||
h.Write(pkixpub) | ||
keyID := h.Sum(nil) | ||
|
||
// TODO: keep a map of used serial numbers to avoid potentially reusing a | ||
// serial multiple times. | ||
serial, err := rand.Int(rand.Reader, maxSerialNumber) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
tmpl := &x509.Certificate{ | ||
SerialNumber: serial, | ||
Subject: pkix.Name{ | ||
CommonName: name, | ||
Organization: []string{organization}, | ||
}, | ||
SubjectKeyId: keyID, | ||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, | ||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | ||
BasicConstraintsValid: true, | ||
NotBefore: time.Now().Add(-validity), | ||
NotAfter: time.Now().Add(validity), | ||
DNSNames: []string{name}, | ||
IsCA: true, | ||
} | ||
|
||
raw, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, pub, priv) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
// Parse certificate bytes so that we have a leaf certificate. | ||
x509c, err := x509.ParseCertificate(raw) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return x509c, priv, nil | ||
} | ||
|
||
// newMITMConfig creates a MITM config using the CA certificate and | ||
// private key to generate on-the-fly certificates. | ||
func newMITMConfig(ca *x509.Certificate, privateKey interface{}, validity time.Duration, organization string) (*mitmConfig, error) { | ||
roots := x509.NewCertPool() | ||
roots.AddCert(ca) | ||
|
||
priv, err := rsa.GenerateKey(rand.Reader, 2048) | ||
if err != nil { | ||
return nil, err | ||
} | ||
pub := priv.Public() | ||
|
||
// Subject Key Identifier support for end entity certificate. | ||
// https://www.ietf.org/rfc/rfc3280.txt (section 4.2.1.2) | ||
pkixpub, err := x509.MarshalPKIXPublicKey(pub) | ||
if err != nil { | ||
return nil, err | ||
} | ||
h := sha1.New() | ||
h.Write(pkixpub) | ||
keyID := h.Sum(nil) | ||
|
||
return &mitmConfig{ | ||
ca: ca, | ||
capriv: privateKey, | ||
priv: priv, | ||
keyID: keyID, | ||
validity: validity, | ||
org: organization, | ||
certs: make(map[string]*tls.Certificate), | ||
roots: roots, | ||
}, nil | ||
} | ||
|
||
// tlsForHost returns a *tls.mitmConfig that will generate certificates on-the-fly | ||
// using the provided hostname | ||
func (c *mitmConfig) tlsForHost(hostname string) *tls.Config { | ||
return &tls.Config{ | ||
InsecureSkipVerify: false, | ||
GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) { | ||
if hostname != clientHello.ServerName { | ||
return nil, fmt.Errorf("hostname %s does not match server name %s", hostname, clientHello.ServerName) | ||
} | ||
|
||
return c.cert(hostname) | ||
}, | ||
NextProtos: []string{"http/1.1"}, | ||
} | ||
} | ||
|
||
func (c *mitmConfig) cert(hostname string) (*tls.Certificate, error) { | ||
// Remove the port if it exists. | ||
host, _, err := net.SplitHostPort(hostname) | ||
if err == nil { | ||
hostname = host | ||
} | ||
|
||
c.certmu.RLock() | ||
tlsc, ok := c.certs[hostname] | ||
c.certmu.RUnlock() | ||
|
||
if ok { | ||
log.Printf("cache hit for %s", hostname) | ||
|
||
// Check validity of the certificate for hostname match, expiry, etc. In | ||
// particular, if the cached certificate has expired, create a new one. | ||
if _, err := tlsc.Leaf.Verify(x509.VerifyOptions{ | ||
DNSName: hostname, | ||
Roots: c.roots, | ||
}); err == nil { | ||
return tlsc, nil | ||
} | ||
|
||
log.Printf("invalid certificate in cache for %s", hostname) | ||
} | ||
|
||
log.Printf("cache miss for %s", hostname) | ||
|
||
serial, err := rand.Int(rand.Reader, maxSerialNumber) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tmpl := &x509.Certificate{SerialNumber: serial, | ||
Subject: pkix.Name{ | ||
CommonName: hostname, | ||
Organization: []string{c.org}, | ||
}, | ||
SubjectKeyId: c.keyID, | ||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | ||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | ||
BasicConstraintsValid: true, | ||
NotBefore: time. | ||
Now().Add(-c.validity), | ||
NotAfter: time.Now().Add(c.validity), | ||
} | ||
|
||
if ip := net.ParseIP(hostname); ip != nil { | ||
tmpl.IPAddresses = []net.IP{ip} | ||
} else { | ||
tmpl.DNSNames = []string{hostname} | ||
} | ||
|
||
raw, err := x509.CreateCertificate(rand.Reader, tmpl, c.ca, c.priv.Public(), c.capriv) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Parse certificate bytes so that we have a leaf certificate. | ||
x509c, err := x509.ParseCertificate(raw) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tlsc = &tls.Certificate{ | ||
Certificate: [][]byte{raw, c.ca.Raw}, | ||
PrivateKey: c.priv, | ||
Leaf: x509c, | ||
} | ||
|
||
c.certmu.Lock() | ||
c.certs[hostname] = tlsc | ||
c.certmu.Unlock() | ||
|
||
return tlsc, nil | ||
} |
Oops, something went wrong.