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