Refactor ssl-passthroug using go to handle TLS hello
This commit is contained in:
parent
d2c7e9008f
commit
de14e2f4f1
11 changed files with 432 additions and 122 deletions
17
vendor/github.com/paultag/sniff/LICENSE
generated
vendored
Normal file
17
vendor/github.com/paultag/sniff/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
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.
|
||||
147
vendor/github.com/paultag/sniff/parser/parser.go
generated
vendored
Normal file
147
vendor/github.com/paultag/sniff/parser/parser.go
generated
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2015
|
||||
*
|
||||
* 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 parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var TLSHeaderLength = 5
|
||||
|
||||
/* This function is basically all most folks want to invoke out of this
|
||||
* jumble of bits. This will take an incoming TLS Client Hello (including
|
||||
* all the fuzzy bits at the beginning of it - fresh out of the socket) and
|
||||
* go ahead and give us the SNI Name they want. */
|
||||
func GetHostname(data []byte) (string, error) {
|
||||
if len(data) == 0 || data[0] != 0x16 {
|
||||
return "", fmt.Errorf("Doesn't look like a TLS Client Hello")
|
||||
}
|
||||
|
||||
extensions, err := GetExtensionBlock(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sn, err := GetSNBlock(extensions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sni, err := GetSNIBlock(sn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(sni), nil
|
||||
}
|
||||
|
||||
/* Given a Server Name TLS Extension block, parse out and return the SNI
|
||||
* (Server Name Indication) payload */
|
||||
func GetSNIBlock(data []byte) ([]byte, error) {
|
||||
index := 0
|
||||
|
||||
for {
|
||||
if index >= len(data) {
|
||||
break
|
||||
}
|
||||
length := int((data[index] << 8) + data[index+1])
|
||||
endIndex := index + 2 + length
|
||||
if data[index+2] == 0x00 { /* SNI */
|
||||
sni := data[index+3:]
|
||||
sniLength := int((sni[0] << 8) + sni[1])
|
||||
return sni[2 : sniLength+2], nil
|
||||
}
|
||||
index = endIndex
|
||||
}
|
||||
return []byte{}, fmt.Errorf(
|
||||
"Finished parsing the SN block without finding an SNI",
|
||||
)
|
||||
}
|
||||
|
||||
/* Given a TLS Extensions data block, go ahead and find the SN block */
|
||||
func GetSNBlock(data []byte) ([]byte, error) {
|
||||
index := 0
|
||||
|
||||
if len(data) < 2 {
|
||||
return []byte{}, fmt.Errorf("Not enough bytes to be an SN block")
|
||||
}
|
||||
|
||||
extensionLength := int((data[index] << 8) + data[index+1])
|
||||
data = data[2 : extensionLength+2]
|
||||
|
||||
for {
|
||||
if index >= len(data) {
|
||||
break
|
||||
}
|
||||
length := int((data[index+2] << 8) + data[index+3])
|
||||
endIndex := index + 4 + length
|
||||
if data[index] == 0x00 && data[index+1] == 0x00 {
|
||||
return data[index+4 : endIndex], nil
|
||||
}
|
||||
|
||||
index = endIndex
|
||||
}
|
||||
|
||||
return []byte{}, fmt.Errorf(
|
||||
"Finished parsing the Extension block without finding an SN block",
|
||||
)
|
||||
}
|
||||
|
||||
/* Given a raw TLS Client Hello, go ahead and find all the Extensions */
|
||||
func GetExtensionBlock(data []byte) ([]byte, error) {
|
||||
/* data[0] - content type
|
||||
* data[1], data[2] - major/minor version
|
||||
* data[3], data[4] - total length
|
||||
* data[...38+5] - start of SessionID (length bit)
|
||||
* data[38+5] - length of SessionID
|
||||
*/
|
||||
var index = TLSHeaderLength + 38
|
||||
|
||||
if len(data) <= index+1 {
|
||||
return []byte{}, fmt.Errorf("Not enough bits to be a Client Hello")
|
||||
}
|
||||
|
||||
/* Index is at SessionID Length bit */
|
||||
if newIndex := index + 1 + int(data[index]); (newIndex + 2) < len(data) {
|
||||
index = newIndex
|
||||
} else {
|
||||
return []byte{}, fmt.Errorf("Not enough bytes for the SessionID")
|
||||
}
|
||||
|
||||
/* Index is at Cipher List Length bits */
|
||||
if newIndex := (index + 2 + int((data[index]<<8)+data[index+1])); (newIndex + 1) < len(data) {
|
||||
index = newIndex
|
||||
} else {
|
||||
return []byte{}, fmt.Errorf("Not enough bytes for the Cipher List")
|
||||
}
|
||||
|
||||
/* Index is now at the compression length bit */
|
||||
if newIndex := index + 1 + int(data[index]); newIndex < len(data) {
|
||||
index = newIndex
|
||||
} else {
|
||||
return []byte{}, fmt.Errorf("Not enough bytes for the compression length")
|
||||
}
|
||||
|
||||
/* Now we're at the Extension start */
|
||||
if len(data[index:]) == 0 {
|
||||
return nil, fmt.Errorf("No extensions")
|
||||
}
|
||||
return data[index:], nil
|
||||
}
|
||||
|
||||
// vim: foldmethod=marker
|
||||
Loading…
Add table
Add a link
Reference in a new issue