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