• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// nghttp2 - HTTP/2 C Library
3//
4// Copyright (c) 2015 Tatsuhiro Tsujikawa
5//
6// Permission is hereby granted, free of charge, to any person obtaining
7// a copy of this software and associated documentation files (the
8// "Software"), to deal in the Software without restriction, including
9// without limitation the rights to use, copy, modify, merge, publish,
10// distribute, sublicense, and/or sell copies of the Software, and to
11// permit persons to whom the Software is furnished to do so, subject to
12// the following conditions:
13//
14// The above copyright notice and this permission notice shall be
15// included in all copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24//
25package main
26
27import (
28	"bytes"
29	"crypto/rand"
30	"encoding/binary"
31	"flag"
32	"fmt"
33	"log"
34	"time"
35
36	"github.com/bradfitz/gomemcache/memcache"
37)
38
39func makeKey(len int) []byte {
40	b := make([]byte, len)
41	if _, err := rand.Read(b); err != nil {
42		log.Fatalf("rand.Read: %v", err)
43	}
44	return b
45}
46
47func main() {
48	var host = flag.String("host", "127.0.0.1", "memcached host")
49	var port = flag.Int("port", 11211, "memcached port")
50	var cipher = flag.String("cipher", "aes-128-cbc", "cipher for TLS ticket encryption")
51	var interval = flag.Int("interval", 3600, "interval to update TLS ticket keys")
52
53	flag.Parse()
54
55	var keylen int
56	switch *cipher {
57	case "aes-128-cbc":
58		keylen = 48
59	case "aes-256-cbc":
60		keylen = 80
61	default:
62		log.Fatalf("cipher: unknown cipher %v", cipher)
63	}
64
65	mc := memcache.New(fmt.Sprintf("%v:%v", *host, *port))
66
67	keys := [][]byte{
68		makeKey(keylen), // current encryption key
69		makeKey(keylen), // next encryption key; now decryption only
70	}
71
72	for {
73		buf := new(bytes.Buffer)
74		if err := binary.Write(buf, binary.BigEndian, uint32(1)); err != nil {
75			log.Fatalf("failed to write version: %v", err)
76		}
77
78		for _, key := range keys {
79			if err := binary.Write(buf, binary.BigEndian, uint16(keylen)); err != nil {
80				log.Fatalf("failed to write length: %v", err)
81			}
82			if _, err := buf.Write(key); err != nil {
83				log.Fatalf("buf.Write: %v", err)
84			}
85		}
86
87		mc.Set(&memcache.Item{
88			Key:        "nghttpx:tls-ticket-key",
89			Value:      buf.Bytes(),
90			Expiration: int32((*interval) + 300),
91		})
92
93		<-time.After(time.Duration(*interval) * time.Second)
94
95		// rotate keys.  the last key is now encryption key.
96		// generate new key and append it to the last, so that
97		// we can at least decrypt TLS ticket encrypted by new
98		// key on the host which does not get new key yet.
99		// keep at most past 11 keys as decryption only key
100		n := len(keys) + 1
101		if n > 13 {
102			n = 13
103		}
104		newKeys := make([][]byte, n)
105		newKeys[0] = keys[len(keys)-1]
106		copy(newKeys[1:], keys[0:n-2])
107		newKeys[n-1] = makeKey(keylen)
108
109		keys = newKeys
110	}
111
112}
113