Files
go-away/lib/challenge/key.go

80 lines
1.6 KiB
Go

package challenge
import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"errors"
"net/http"
"time"
)
type Key [KeySize]byte
const KeySize = sha256.Size
func (k *Key) Set(flags KeyFlags) {
(*k)[0] |= uint8(flags)
}
func (k *Key) Get(flags KeyFlags) KeyFlags {
return KeyFlags((*k)[0] & uint8(flags))
}
func (k *Key) Unset(flags KeyFlags) {
(*k)[0] = (*k)[0] & ^(uint8(flags))
}
type KeyFlags uint8
const (
KeyFlagIsIPv4 = KeyFlags(1 << iota)
)
func KeyFromString(s string) (Key, error) {
b, err := hex.DecodeString(s)
if err != nil {
return Key{}, err
}
if len(b) != KeySize {
return Key{}, errors.New("invalid challenge key")
}
return Key(b), nil
}
func GetChallengeKeyForRequest(state StateInterface, reg *Registration, until time.Time, r *http.Request) Key {
data := RequestDataFromContext(r.Context())
hasher := sha256.New()
hasher.Write([]byte("challenge\x00"))
hasher.Write([]byte(reg.Name))
hasher.Write([]byte{0})
keyAddr := data.NetworkPrefix().As16()
hasher.Write(keyAddr[:])
hasher.Write([]byte{0})
// specific headers
for _, k := range reg.KeyHeaders {
hasher.Write([]byte(k))
hasher.Write([]byte{0})
for _, v := range r.Header.Values(k) {
hasher.Write([]byte(v))
hasher.Write([]byte{1})
}
hasher.Write([]byte{0})
}
hasher.Write([]byte{0})
_ = binary.Write(hasher, binary.LittleEndian, until.UTC().Unix())
hasher.Write([]byte{0})
hasher.Write(state.PrivateKeyFingerprint())
hasher.Write([]byte{0})
sum := Key(hasher.Sum(nil))
sum[0] = 0
if data.RemoteAddress.Addr().Unmap().Is4() {
// Is IPv4, mark
sum.Set(KeyFlagIsIPv4)
}
return Key(sum)
}