|
|
|
@ -21,6 +21,7 @@ import (
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"crypto/x509"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"golang.org/x/net/idna"
|
|
|
|
|
)
|
|
|
|
@ -28,7 +29,12 @@ import (
|
|
|
|
|
var builtinPinDB *hpkpDatabase
|
|
|
|
|
|
|
|
|
|
type hpkpDatabase struct {
|
|
|
|
|
pins map[string]map[string]bool
|
|
|
|
|
pins map[string]*pinEntry
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type pinEntry struct {
|
|
|
|
|
digests map[string]bool
|
|
|
|
|
expiry time.Time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (db *hpkpDatabase) HasPins(host string) (string, bool) {
|
|
|
|
@ -42,12 +48,17 @@ func (db *hpkpDatabase) Validate(host string, chains [][]*x509.Certificate) bool
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pins := db.pins[host]
|
|
|
|
|
entry := db.pins[host]
|
|
|
|
|
if time.Now().After(entry.expiry) {
|
|
|
|
|
// If the pins are expired, assume that it is valid.
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, chain := range chains {
|
|
|
|
|
for _, cert := range chain {
|
|
|
|
|
derivedPin := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
|
|
|
|
|
derivedPinEncoded := base64.StdEncoding.EncodeToString(derivedPin[:])
|
|
|
|
|
if !pins[derivedPinEncoded] {
|
|
|
|
|
if !entry.digests[derivedPinEncoded] {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -56,7 +67,7 @@ func (db *hpkpDatabase) Validate(host string, chains [][]*x509.Certificate) bool
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (db *hpkpDatabase) Add(host string, pins []string) {
|
|
|
|
|
func (db *hpkpDatabase) Add(host string, pins []string, expiry time.Time) {
|
|
|
|
|
h, err := normalizeHost(host)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic("failed to add hpkp pin, invalid host: " + err.Error())
|
|
|
|
@ -67,7 +78,10 @@ func (db *hpkpDatabase) Add(host string, pins []string) {
|
|
|
|
|
pinMap[pin] = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db.pins[h] = pinMap
|
|
|
|
|
db.pins[h] = &pinEntry{
|
|
|
|
|
digests: pinMap,
|
|
|
|
|
expiry: expiry,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func normalizeHost(host string) (string, error) {
|
|
|
|
@ -76,13 +90,18 @@ func normalizeHost(host string) (string, error) {
|
|
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
builtinPinDB = &hpkpDatabase{
|
|
|
|
|
pins: make(map[string]map[string]bool),
|
|
|
|
|
pins: make(map[string]*pinEntry),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generated on 2019-02-04.
|
|
|
|
|
builtinPinDB.Add("ajax.aspnetcdn.com", []string{
|
|
|
|
|
"PPjoAKk+kCVr9VNPXJkyHXEKnIyd5t5NqpPL3zCvJOE=",
|
|
|
|
|
"wBdPad95AU7OgLRs0FU/E6ILO1MSCM84kJ9y0H+TT7s=",
|
|
|
|
|
"Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=",
|
|
|
|
|
})
|
|
|
|
|
// Generated on 2019-02-04, expiry set to the expiration date
|
|
|
|
|
// of the leaf, which is the earliest in the chain.
|
|
|
|
|
builtinPinDB.Add(
|
|
|
|
|
"ajax.aspnetcdn.com",
|
|
|
|
|
[]string{
|
|
|
|
|
"PPjoAKk+kCVr9VNPXJkyHXEKnIyd5t5NqpPL3zCvJOE=",
|
|
|
|
|
"wBdPad95AU7OgLRs0FU/E6ILO1MSCM84kJ9y0H+TT7s=",
|
|
|
|
|
"Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=",
|
|
|
|
|
},
|
|
|
|
|
time.Date(2020, time.March, 30, 17, 48, 56, 0, time.UTC),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|