• 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	"github.com/bradfitz/gomemcache/memcache"
34	"log"
35	"time"
36)
37
38func makeKey(len int) []byte {
39	b := make([]byte, len)
40	if _, err := rand.Read(b); err != nil {
41		log.Fatalf("rand.Read: %v", err)
42	}
43	return b
44}
45
46func main() {
47	var host = flag.String("host", "127.0.0.1", "memcached host")
48	var port = flag.Int("port", 11211, "memcached port")
49	var cipher = flag.String("cipher", "aes-128-cbc", "cipher for TLS ticket encryption")
50	var interval = flag.Int("interval", 3600, "interval to update TLS ticket keys")
51
52	flag.Parse()
53
54	var keylen int
55	switch *cipher {
56	case "aes-128-cbc":
57		keylen = 48
58	case "aes-256-cbc":
59		keylen = 80
60	default:
61		log.Fatalf("cipher: unknown cipher %v", cipher)
62	}
63
64	mc := memcache.New(fmt.Sprintf("%v:%v", *host, *port))
65
66	keys := [][]byte{
67		makeKey(keylen), // current encryption key
68		makeKey(keylen), // next encryption key; now decryption only
69	}
70
71	for {
72		buf := new(bytes.Buffer)
73		if err := binary.Write(buf, binary.BigEndian, uint32(1)); err != nil {
74			log.Fatalf("failed to write version: %v", err)
75		}
76
77		for _, key := range keys {
78			if err := binary.Write(buf, binary.BigEndian, uint16(keylen)); err != nil {
79				log.Fatalf("failed to write length: %v", err)
80			}
81			if _, err := buf.Write(key); err != nil {
82				log.Fatalf("buf.Write: %v", err)
83			}
84		}
85
86		mc.Set(&memcache.Item{
87			Key:        "nghttpx:tls-ticket-key",
88			Value:      buf.Bytes(),
89			Expiration: int32((*interval) + 300),
90		})
91
92		select {
93		case <-time.After(time.Duration(*interval) * time.Second):
94		}
95
96		// rotate keys.  the last key is now encryption key.
97		// generate new key and append it to the last, so that
98		// we can at least decrypt TLS ticket encrypted by new
99		// key on the host which does not get new key yet.
100		// keep at most past 11 keys as decryption only key
101		n := len(keys) + 1
102		if n > 13 {
103			n = 13
104		}
105		newKeys := make([][]byte, n)
106		newKeys[0] = keys[len(keys)-1]
107		copy(newKeys[1:], keys[0:n-2])
108		newKeys[n-1] = makeKey(keylen)
109
110		keys = newKeys
111	}
112
113}
114