114 lines
3.2 KiB
Go
114 lines
3.2 KiB
Go
//
|
|
// nghttp2 - HTTP/2 C Library
|
|
//
|
|
// Copyright (c) 2015 Tatsuhiro Tsujikawa
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"flag"
|
|
"fmt"
|
|
"github.com/bradfitz/gomemcache/memcache"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
func makeKey(len int) []byte {
|
|
b := make([]byte, len)
|
|
if _, err := rand.Read(b); err != nil {
|
|
log.Fatalf("rand.Read: %v", err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func main() {
|
|
var host = flag.String("host", "127.0.0.1", "memcached host")
|
|
var port = flag.Int("port", 11211, "memcached port")
|
|
var cipher = flag.String("cipher", "aes-128-cbc", "cipher for TLS ticket encryption")
|
|
var interval = flag.Int("interval", 3600, "interval to update TLS ticket keys")
|
|
|
|
flag.Parse()
|
|
|
|
var keylen int
|
|
switch *cipher {
|
|
case "aes-128-cbc":
|
|
keylen = 48
|
|
case "aes-256-cbc":
|
|
keylen = 80
|
|
default:
|
|
log.Fatalf("cipher: unknown cipher %v", cipher)
|
|
}
|
|
|
|
mc := memcache.New(fmt.Sprintf("%v:%v", *host, *port))
|
|
|
|
keys := [][]byte{
|
|
makeKey(keylen), // current encryption key
|
|
makeKey(keylen), // next encryption key; now decryption only
|
|
}
|
|
|
|
for {
|
|
buf := new(bytes.Buffer)
|
|
if err := binary.Write(buf, binary.BigEndian, uint32(1)); err != nil {
|
|
log.Fatalf("failed to write version: %v", err)
|
|
}
|
|
|
|
for _, key := range keys {
|
|
if err := binary.Write(buf, binary.BigEndian, uint16(keylen)); err != nil {
|
|
log.Fatalf("failed to write length: %v", err)
|
|
}
|
|
if _, err := buf.Write(key); err != nil {
|
|
log.Fatalf("buf.Write: %v", err)
|
|
}
|
|
}
|
|
|
|
mc.Set(&memcache.Item{
|
|
Key: "nghttpx:tls-ticket-key",
|
|
Value: buf.Bytes(),
|
|
Expiration: int32((*interval) + 300),
|
|
})
|
|
|
|
select {
|
|
case <-time.After(time.Duration(*interval) * time.Second):
|
|
}
|
|
|
|
// rotate keys. the last key is now encryption key.
|
|
// generate new key and append it to the last, so that
|
|
// we can at least decrypt TLS ticket encrypted by new
|
|
// key on the host which does not get new key yet.
|
|
// keep at most past 11 keys as decryption only key
|
|
n := len(keys) + 1
|
|
if n > 13 {
|
|
n = 13
|
|
}
|
|
newKeys := make([][]byte, n)
|
|
newKeys[0] = keys[len(keys)-1]
|
|
copy(newKeys[1:], keys[0:n-2])
|
|
newKeys[n-1] = makeKey(keylen)
|
|
|
|
keys = newKeys
|
|
}
|
|
|
|
}
|