@ -2,133 +2,638 @@ package sgfw
import (
import (
"crypto/x509"
"crypto/x509"
"encoding/binary"
// "encoding/hex"
"errors"
"errors"
"fmt"
"fmt"
"io"
"io"
"net"
"net"
"time"
"time"
"math/rand"
)
)
const TLSGUARD_READ_TIMEOUT = 2 * time . Second
const TLSGUARD_READ_TIMEOUT = 8 * time . Second
const TLSGUARD_MIN_TLS_VER_MAJ = 3
const TLSGUARD_MIN_TLS_VER_MAJ = 3
const TLSGUARD_MIN_TLS_VER_MIN = 1
const TLSGUARD_MIN_TLS_VER_MIN = 1
const TLS_RECORD_HDR_LEN = 5
const SSL3_RT_CHANGE_CIPHER_SPEC = 20
const SSL3_RT_CHANGE_CIPHER_SPEC = 20
const SSL3_RT_ALERT = 21
const SSL3_RT_ALERT = 21
const SSL3_RT_HANDSHAKE = 22
const SSL3_RT_HANDSHAKE = 22
const SSL3_RT_APPLICATION_DATA = 23
const SSL3_RT_APPLICATION_DATA = 23
const SSL3_MT_HELLO_REQUEST = 0
const SSL3_MT_CLIENT_HELLO = 1
const SSL3_MT_SERVER_HELLO = 2
const SSL3_MT_SERVER_HELLO = 2
const SSL3_MT_CERTIFICATE = 11
const SSL3_MT_CERTIFICATE = 11
const SSL3_MT_CERTIFICATE_REQUEST = 13
const SSL3_MT_CERTIFICATE_REQUEST = 13
const SSL3_MT_SERVER_DONE = 14
const SSL3_MT_SERVER_DONE = 14
const SSL3_MT_CERTIFICATE_STATUS = 22
const SSL3_AL_WARNING = 1
const SSL3_AL_FATAL = 2
const SSL3_AD_CLOSE_NOTIFY = 0
const SSL3_AD_UNEXPECTED_MESSAGE = 10
const SSL3_AD_BAD_RECORD_MAC = 20
const TLS1_AD_DECRYPTION_FAILED = 21
const TLS1_AD_RECORD_OVERFLOW = 22
const SSL3_AD_DECOMPRESSION_FAILURE = 30
const SSL3_AD_HANDSHAKE_FAILURE = 40
const SSL3_AD_NO_CERTIFICATE = 41
const SSL3_AD_BAD_CERTIFICATE = 42
const SSL3_AD_UNSUPPORTED_CERTIFICATE = 43
const SSL3_AD_CERTIFICATE_REVOKED = 44
const SSL3_AD_CERTIFICATE_EXPIRED = 45
const SSL3_AD_CERTIFICATE_UNKNOWN = 46
const SSL3_AD_ILLEGAL_PARAMETER = 47
const TLS1_AD_UNKNOWN_CA = 48
const TLS1_AD_ACCESS_DENIED = 49
const TLS1_AD_DECODE_ERROR = 50
const TLS1_AD_DECRYPT_ERROR = 51
const TLS1_AD_EXPORT_RESTRICTION = 60
const TLS1_AD_PROTOCOL_VERSION = 70
const TLS1_AD_INSUFFICIENT_SECURITY = 71
const TLS1_AD_INTERNAL_ERROR = 80
const TLS1_AD_INAPPROPRIATE_FALLBACK = 86
const TLS1_AD_USER_CANCELLED = 90
const TLS1_AD_NO_RENEGOTIATION = 100
const TLS1_AD_UNSUPPORTED_EXTENSION = 110
const TLSEXT_TYPE_server_name = 0
const TLSEXT_TYPE_max_fragment_length = 1
const TLSEXT_TYPE_client_certificate_url = 2
const TLSEXT_TYPE_trusted_ca_keys = 3
const TLSEXT_TYPE_truncated_hmac = 4
const TLSEXT_TYPE_status_request = 5
const TLSEXT_TYPE_user_mapping = 6
const TLSEXT_TYPE_client_authz = 7
const TLSEXT_TYPE_server_authz = 8
const TLSEXT_TYPE_cert_type = 9
const TLSEXT_TYPE_supported_groups = 10
const TLSEXT_TYPE_ec_point_formats = 11
const TLSEXT_TYPE_srp = 12
const TLSEXT_TYPE_signature_algorithms = 13
const TLSEXT_TYPE_use_srtp = 14
const TLSEXT_TYPE_heartbeat = 15
const TLSEXT_TYPE_application_layer_protocol_negotiation = 16
const TLSEXT_TYPE_status_request_v2 = 17
const TLSEXT_TYPE_signed_certificate_timestamp = 18
const TLSEXT_TYPE_client_certificate_type = 19
const TLSEXT_TYPE_server_certificate_type = 20
const TLSEXT_TYPE_padding = 21
const TLSEXT_TYPE_encrypt_then_mac = 22
const TLSEXT_TYPE_extended_master_secret = 23
const TLSEXT_TYPE_token_binding = 24
const TLSEXT_TYPE_cached_info = 25
const TLSEXT_TYPE_SessionTicket = 35
const TLSEXT_TYPE_renegotiate = 0xff01
var tlsExtensionMap map [ uint16 ] string = map [ uint16 ] string {
TLSEXT_TYPE_server_name : "TLSEXT_TYPE_server_name" ,
TLSEXT_TYPE_max_fragment_length : "TLSEXT_TYPE_max_fragment_length" ,
TLSEXT_TYPE_client_certificate_url : "TLSEXT_TYPE_client_certificate_url" ,
TLSEXT_TYPE_trusted_ca_keys : "TLSEXT_TYPE_trusted_ca_keys" ,
TLSEXT_TYPE_truncated_hmac : "TLSEXT_TYPE_truncated_hmac" ,
TLSEXT_TYPE_status_request : "TLSEXT_TYPE_status_request" ,
TLSEXT_TYPE_user_mapping : "TLSEXT_TYPE_user_mapping" ,
TLSEXT_TYPE_client_authz : "TLSEXT_TYPE_client_authz" ,
TLSEXT_TYPE_server_authz : "TLSEXT_TYPE_server_authz" ,
TLSEXT_TYPE_cert_type : "TLSEXT_TYPE_cert_type" ,
TLSEXT_TYPE_supported_groups : "TLSEXT_TYPE_supported_groups" ,
TLSEXT_TYPE_ec_point_formats : "TLSEXT_TYPE_ec_point_formats" ,
TLSEXT_TYPE_srp : "TLSEXT_TYPE_srp" ,
TLSEXT_TYPE_signature_algorithms : "TLSEXT_TYPE_signature_algorithms" ,
TLSEXT_TYPE_use_srtp : "TLSEXT_TYPE_use_srtp" ,
TLSEXT_TYPE_heartbeat : "TLSEXT_TYPE_heartbeat" ,
TLSEXT_TYPE_application_layer_protocol_negotiation : "TLSEXT_TYPE_application_layer_protocol_negotiation" ,
TLSEXT_TYPE_status_request_v2 : "TLSEXT_TYPE_status_request_v2" ,
TLSEXT_TYPE_signed_certificate_timestamp : "TLSEXT_TYPE_signed_certificate_timestamp" ,
TLSEXT_TYPE_client_certificate_type : "TLSEXT_TYPE_client_certificate_type" ,
TLSEXT_TYPE_server_certificate_type : "TLSEXT_TYPE_server_certificate_type" ,
TLSEXT_TYPE_padding : "TLSEXT_TYPE_padding" ,
TLSEXT_TYPE_encrypt_then_mac : "TLSEXT_TYPE_encrypt_then_mac" ,
TLSEXT_TYPE_extended_master_secret : "TLSEXT_TYPE_extended_master_secret" ,
TLSEXT_TYPE_token_binding : "TLSEXT_TYPE_token_binding" ,
TLSEXT_TYPE_cached_info : "TLSEXT_TYPE_cached_info" ,
TLSEXT_TYPE_SessionTicket : "TLSEXT_TYPE_SessionTicket" ,
TLSEXT_TYPE_renegotiate : "TLSEXT_TYPE_renegotiate" ,
}
type connReader struct {
client bool
data [ ] byte
rtype int
err error
numb int
}
var cipherSuiteMap map [ uint16 ] string = map [ uint16 ] string {
0x0000 : "TLS_NULL_WITH_NULL_NULL" ,
0x000a : "TLS_RSA_WITH_3DES_EDE_CBC_SHA" ,
0x002f : "TLS_RSA_WITH_AES_128_CBC_SHA" ,
0x0033 : "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" ,
0x0039 : "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" ,
0x0035 : "TLS_RSA_WITH_AES_256_CBC_SHA" ,
0x0030 : "TLS_DH_DSS_WITH_AES_128_CBC_SHA" ,
0x0067 : "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256" ,
0x006b : "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" ,
0x009e : "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" ,
0x009f : "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384" ,
0x00c4 : "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256" ,
0xc009 : "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" ,
0xc00a : "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" ,
0xc013 : "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" ,
0xc014 : "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" ,
0xc023 : "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" ,
0xc024 : "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" ,
0xc027 : "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" ,
0xc028 : "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" ,
0xc02b : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ,
0xc02c : "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" ,
0xc02f : "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" ,
0xc030 : "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" ,
0xc076 : "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256" ,
0xc077 : "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384" ,
0xcc13 : "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ,
0xcc14 : "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" ,
0xcc15 : "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ,
0xcca9 : "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" ,
0xcca8 : "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ,
}
var whitelistedCiphers = [ ] string {
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA" ,
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA" ,
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" ,
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384" ,
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ,
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" ,
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" ,
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" ,
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" ,
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ,
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" ,
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" ,
"TLS_RSA_WITH_AES_128_CBC_SHA" ,
"SSL_RSA_WITH_3DES_EDE_CBC_SHA" ,
}
var blacklistedCiphers = [ ] string {
"TLS_NULL_WITH_NULL_NULL" ,
"TLS_RSA_WITH_AES_128_CBC_SHA" ,
}
func getCipherSuiteName ( value uint ) string {
val , ok := cipherSuiteMap [ uint16 ( value ) ]
if ! ok {
return "UNKNOWN"
}
return val
}
func isBadCipher ( cname string ) bool {
for _ , cipher := range blacklistedCiphers {
if cipher == cname {
return true
}
}
return false
}
func gettlsExtensionName ( value uint ) string {
// 26-34: Unassigned
// 36-65280: Unassigned
// 65282-65535: Unassigned
if ( value >= 26 && value <= 34 ) || ( value >= 36 && value <= 65280 ) || ( value >= 65282 && value <= 65535 ) {
return fmt . Sprintf ( "Unassigned TLS Extension %#x" , value )
}
val , ok := tlsExtensionMap [ uint16 ( value ) ]
if ! ok {
return "UNKNOWN"
}
return val
}
func stripTLSData ( record [ ] byte , start_ind , end_ind int , len_ind int , len_size int ) [ ] byte {
var size uint = 0
if len_size < 1 || len_size > 2 {
return nil
} else if start_ind >= end_ind {
return nil
} else if len_ind >= start_ind {
return nil
}
rcopy := make ( [ ] byte , len ( record ) )
copy ( rcopy , record )
if len_size == 1 {
size = uint ( rcopy [ len_ind ] )
} else if len_size == 2 {
size = uint ( binary . BigEndian . Uint16 ( rcopy [ len_ind : len_ind + len_size ] ) )
}
size -= uint ( end_ind - start_ind )
func readTLSChunk ( conn net . Conn ) ( [ ] byte , int , error ) {
// Put back the length size
if len_size == 1 {
rcopy [ len_ind ] = byte ( size )
} else if len_size == 2 {
binary . BigEndian . PutUint16 ( rcopy [ len_ind : len_ind + len_size ] , uint16 ( size ) )
}
// Patch the record size
rsize := binary . BigEndian . Uint16 ( rcopy [ 3 : 5 ] )
rsize -= uint16 ( end_ind - start_ind )
binary . BigEndian . PutUint16 ( rcopy [ 3 : 5 ] , rsize )
// And finally the 3 byte hello record
hsize := binary . BigEndian . Uint32 ( rcopy [ 5 : 9 ] )
saved_b := hsize & 0xff000000
hsize &= 0x00ffffff
hsize -= uint32 ( end_ind - start_ind )
hsize |= saved_b
binary . BigEndian . PutUint32 ( rcopy [ 5 : 9 ] , hsize )
result := append ( rcopy [ : start_ind ] , rcopy [ end_ind : ] ... )
return result
}
func connectionReader ( conn net . Conn , is_client bool , c chan connReader , done chan bool , num int ) {
var ret_error error = nil
buffered := [ ] byte { }
mlen := 0
rtype := 0
stage := 1
proceed := true
for {
if ret_error != nil {
cr := connReader { client : is_client , data : nil , rtype : 0 , err : ret_error , numb : num }
c <- cr
break
}
//fmt.Printf("why i am here %v %d\n", is_client, num)
//if is_client == true && proceed == false {
if proceed == false {
if len ( buffered ) > 0 {
c <- connReader { client : is_client , data : buffered , rtype : 0 , err : nil , numb : num }
}
c <- connReader { client : is_client , data : nil , rtype : 0 , err : nil }
return
}
select {
case <- done :
// fmt.Printf("++ DONE %d: %v\n", num, is_client)
if len ( buffered ) > 0 {
// fmt.Printf("++ DONE BUT DISPOSING OF BUFFERED DATA num: %d\n", num)
c <- connReader { client : is_client , data : buffered , rtype : 0 , err : nil , numb : num }
}
c <- connReader { client : is_client , data : nil , rtype : 0 , err : nil , numb : num }
return
default :
if stage == 1 && proceed == true {
header := make ( [ ] byte , TLS_RECORD_HDR_LEN )
conn . SetReadDeadline ( time . Now ( ) . Add ( TLSGUARD_READ_TIMEOUT ) )
conn . SetReadDeadline ( time . Now ( ) . Add ( TLSGUARD_READ_TIMEOUT ) )
cbytes , err := readNBytes ( conn , 5 )
// fmt.Printf("About to read here stage 1 %v %d\n", is_client, num)
_ , err := io . ReadFull ( conn , header )
// fmt.Printf("Read here stage 1 %v num %d \n", is_client, num)
conn . SetReadDeadline ( time . Time { } )
conn . SetReadDeadline ( time . Time { } )
if err != nil {
if err != nil {
log . Errorf ( "TLS data chunk read failure: " , err )
ret_error = err
return nil , 0 , err
continue
}
}
if int ( cbytes [ 1 ] ) < TLSGUARD_MIN_TLS_VER_MAJ {
if int ( header [ 1 ] ) < TLSGUARD_MIN_TLS_VER_MAJ {
return nil , 0 , errors . New ( "TLS protocol major version less than expected minimum" )
ret_error = errors . New ( "TLS protocol major version less than expected minimum" )
} else if int ( cbytes [ 2 ] ) < TLSGUARD_MIN_TLS_VER_MIN {
continue
return nil , 0 , errors . New ( "TLS protocol minor version less than expected minimum" )
} else if int ( header [ 2 ] ) < TLSGUARD_MIN_TLS_VER_MIN {
ret_error = errors . New ( "TLS protocol minor version less than expected minimum" )
continue
} else if int ( header [ 1 ] ) > 3 {
ret_error = errors . New ( "TLS protocol major version was larger than expected; maybe not TLS handshake?" )
continue
}
}
cbyte := cbytes [ 0 ]
rtype = int ( header [ 0 ] )
mlen := int ( int ( cbytes [ 3 ] ) << 8 | int ( cbytes [ 4 ] ) )
mlen = int ( int ( header [ 3 ] ) << 8 | int ( header [ 4 ] ) )
// fmt.Printf("TLS data chunk header read: type = %#x, maj = %v, min = %v, len = %v\n", cbyte, cbytes[1], cbytes[2], mlen)
// fmt.Printf("TLS data chunk header read: type = %#x, maj = %v, min = %v, len = %v\n", rtype, header[1], header [2], mlen)
/* 16384+1024 if compression is not null */
/* or 16384+2048 if ciphertext */
if mlen > 16384 {
ret_error = errors . New ( fmt . Sprintf ( "TLSGuard read TLS plaintext record of excessively large length; dropping (%v bytes)" , mlen ) )
continue
}
buffered = header
stage ++
} else if stage == 2 {
remainder := make ( [ ] byte , mlen )
// fmt.Printf("About to read here stage 2 %v num %d\n", is_client, num)
conn . SetReadDeadline ( time . Now ( ) . Add ( TLSGUARD_READ_TIMEOUT ) )
conn . SetReadDeadline ( time . Now ( ) . Add ( TLSGUARD_READ_TIMEOUT ) )
cbytes2 , err := readNBytes ( conn , mlen )
_ , err := io . ReadFull ( conn , remainder )
conn . SetReadDeadline ( time . Time { } )
conn . SetReadDeadline ( time . Time { } )
if err != nil {
if err != nil {
return nil , 0 , err
ret_error = err
continue
}
buffered = append ( buffered , remainder ... )
// fmt.Printf("------- CHUNK READ: client: %v, err = %v, bytes = %v\n", is_client, err, len(buffered))
cr := connReader { client : is_client , data : buffered , rtype : rtype , err : err , numb : num }
c <- cr
buffered = [ ] byte { }
rtype = 0
mlen = 0
stage = 1
//proceed = false
if is_client {
proceed = false
}
}
}
}
}
}
cbytes = append ( cbytes , cbytes2 ... )
func isExpected ( val uint , possibilities [ ] uint ) bool {
return cbytes , int ( cbyte ) , nil
for _ , pval := range possibilities {
if val == pval {
return true
}
}
return false
}
}
func TLSGuard ( conn , conn2 net . Conn , fqdn string ) error {
func TLSGuard ( conn , conn2 net . Conn , fqdn string ) error {
x509Valid := false
ndone := 0
// Should this be a requirement?
// Should this be a requirement?
// if strings.HasSuffix(request.DestAddr.FQDN, "onion") {
// if strings.HasSuffix(request.DestAddr.FQDN, "onion") {
//conn client
//conn client
//conn2 server
//conn2 server
// Read the opening message from the client
// fmt.Println("-------- STARTING HANDSHAKE LOOP")
chunk , rtype , err := readTLSChunk ( conn )
crChan := make ( chan connReader )
if err != nil {
dChan := make ( chan bool , 10 )
return err
dChan2 := make ( chan bool , 10 )
rand . Seed ( time . Now ( ) . UTC ( ) . UnixNano ( ) )
connectThread1 := rand . Intn ( 1000 )
connectThread2 := rand . Intn ( 1000 )
go connectionReader ( conn , true , crChan , dChan , connectThread1 )
go connectionReader ( conn2 , false , crChan , dChan2 , connectThread2 )
client_expected := [ ] uint { SSL3_MT_CLIENT_HELLO }
server_expected := [ ] uint { SSL3_MT_SERVER_HELLO }
client_sess := false
server_sess := false
client_change_cipher := false
server_change_cipher := false
select_loop :
for {
if ndone == 2 {
// fmt.Println("DONE channel got both notifications. Terminating loop.")
close ( dChan )
close ( dChan2 )
close ( crChan )
break
}
}
if rtype != SSL3_RT_HANDSHAKE {
select {
return errors . New ( "Blocked client from attempting non-TLS connection" )
case cr := <- crChan :
other := conn
if cr . client {
other = conn2
}
}
// Pass it on through to the server
//fmt.Printf("++++ SELECT: %v, %v, %v\n", cr.client, cr.err, len(cr.data))
conn2 . Write ( chunk )
if cr . err == nil && cr . data == nil {
// fmt.Println("DONE channel notification received")
ndone ++
continue
}
// Read ServerHello
if cr . err == nil {
valid := false
if cr . rtype == SSL3_RT_CHANGE_CIPHER_SPEC || cr . rtype == SSL3_RT_APPLICATION_DATA ||
loop := 1
cr . rtype == SSL3_RT_ALERT {
passthru := false
/* We expect only a single byte of data */
if cr . rtype == SSL3_RT_CHANGE_CIPHER_SPEC {
// fmt.Println("CHANGE CIPHER_SPEC: ", cr.data[TLS_RECORD_HDR_LEN])
if len ( cr . data ) != 6 {
return errors . New ( fmt . Sprintf ( "TLSGuard dropped connection with strange change cipher spec data length (%v bytes)" , len ( cr . data ) ) )
}
if cr . data [ TLS_RECORD_HDR_LEN ] != 1 {
return errors . New ( fmt . Sprintf ( "TLSGuard dropped connection with strange change cipher spec data (%#x bytes)" , cr . data [ TLS_RECORD_HDR_LEN ] ) )
}
for 1 == 1 {
if cr . client {
loop ++
client_change_cipher = true
} else {
server_change_cipher = true
x509Valid = true
dChan <- true
dChan2 <- true
}
} else if cr . rtype == SSL3_RT_ALERT {
if cr . data [ TLS_RECORD_HDR_LEN ] == SSL3_AL_WARNING {
fmt . Println ( "SSL ALERT TYPE: warning" )
} else if cr . data [ TLS_RECORD_HDR_LEN ] == SSL3_AL_FATAL {
fmt . Println ( "SSL ALERT TYPE: fatal" )
} else {
fmt . Println ( "SSL ALERT TYPE UNKNOWN" )
}
// fmt.Printf("SSL LOOP %v; trying to read: conn2\n", loop)
alert_desc := int ( int ( cr . data [ 5 ] ) << 8 | int ( cr . data [ 6 ] ) )
chunk , rtype , err = readTLSChunk ( conn2 )
fmt . Println ( "ALERT DESCRIPTION: " , alert_desc )
if err != nil {
if cr . data [ TLS_RECORD_HDR_LEN ] == SSL3_AL_FATAL {
log . Debugf ( "TLSGUARD: OTHER loop %v: trying to read: conn\n" , loop )
return errors . New ( fmt . Sprintf ( "TLSGuard dropped connection after fatal error alert detected" ) )
chunk , rtype , err2 := readTLSChunk ( conn )
} else if alert_desc == SSL3_AD_CLOSE_NOTIFY {
log . Debugf ( "TLSGUARD: read: %v, %v, %v\n" , err2 , rtype , len ( chunk ) )
return errors . New ( fmt . Sprintf ( "TLSGuard dropped connection after close_notify alert detected" ) )
}
if err2 == nil {
}
conn2 . Write ( chunk )
other . Write ( cr . data )
continue
continue
} else if cr . rtype != SSL3_RT_HANDSHAKE {
return errors . New ( fmt . Sprintf ( "Expected TLS server handshake byte was not received [%#x vs 0x16]" , cr . rtype ) )
}
}
return err
handshakeMsg := cr . data [ TLS_RECORD_HDR_LEN : ]
s := uint ( handshakeMsg [ 0 ] )
handshakeMessageLen := handshakeMsg [ 1 : 4 ]
handshakeMessageLenInt := int ( int ( handshakeMessageLen [ 0 ] ) << 16 | int ( handshakeMessageLen [ 1 ] ) << 8 | int ( handshakeMessageLen [ 2 ] ) )
// fmt.Printf("s = %#x, lenint = %v, total = %d\n", s, handshakeMessageLenInt, len(cr.data))
if ( client_sess || server_sess ) && ( client_change_cipher || server_change_cipher ) {
if handshakeMessageLenInt > len ( cr . data ) + 9 {
log . Notice ( "TLSGuard saw what looks like a resumed encrypted session... passing connection through" )
x509Valid = true
other . Write ( cr . data )
dChan2 <- true
dChan <- true
break select_loop
}
}
if cr . client && ! isExpected ( s , client_expected ) {
return errors . New ( fmt . Sprintf ( "Client sent handshake type %#x but expected %#x" , s , client_expected ) )
} else if ! cr . client && ! isExpected ( s , server_expected ) {
return errors . New ( fmt . Sprintf ( "Server sent handshake type %#x but expected %#x" , s , server_expected ) )
}
if ( cr . client && s == SSL3_MT_CLIENT_HELLO ) || ( ! cr . client && s == SSL3_MT_SERVER_HELLO ) {
// rewrite := false
// rewrite_buf := []byte{}
//SRC := ""
if s != SSL3_MT_CLIENT_HELLO {
//SRC = "CLIENT"
//} else {
server_expected = [ ] uint { SSL3_MT_CERTIFICATE , SSL3_MT_HELLO_REQUEST }
// SRC = "SERVER"
}
hello_offset := 4
// 2 byte protocol version
// fmt.Println(SRC, "HELLO VERSION = ", handshakeMsg[hello_offset:hello_offset+2])
hello_offset += 2
// 4 byte Random/GMT time
//gmtbytes := binary.BigEndian.Uint32(handshakeMsg[hello_offset : hello_offset+4])
//gmt := time.Unix(int64(gmtbytes), 0)
//fmt.Println(SRC, "HELLO GMT = ", gmt)
hello_offset += 4
// 28 bytes Random/random_bytes
hello_offset += 28
// 1 byte (32-bit session ID)
sess_len := uint ( handshakeMsg [ hello_offset ] )
// fmt.Println(SRC, "HELLO SESSION ID = ", sess_len)
if cr . client && sess_len > 0 {
client_sess = true
} else {
server_sess = true
}
/ *
hello_offset += int ( sess_len ) + 1
// 2 byte cipher suite array
cs := binary . BigEndian . Uint16 ( handshakeMsg [ hello_offset : hello_offset + 2 ] )
noCS := cs
fmt . Printf ( "cs = %v / %#x\n" , noCS , noCS )
saved_ciphersuite_size_off := hello_offset
if ! cr . client {
fmt . Printf ( "SERVER selected ciphersuite: %#x (%s)\n" , cs , getCipherSuiteName ( uint ( cs ) ) )
hello_offset += 2
} else {
for csind := 0 ; csind < int ( noCS / 2 ) ; csind ++ {
off := hello_offset + 2 + ( csind * 2 )
cs = binary . BigEndian . Uint16 ( handshakeMsg [ off : off + 2 ] )
cname := getCipherSuiteName ( uint ( cs ) )
fmt . Printf ( "%s HELLO CIPHERSUITE: %d/%d: %#x (%s)\n" , SRC , csind + 1 , noCS / 2 , cs , cname )
if isBadCipher ( cname ) {
fmt . Println ( "BAD CIPHER: " , cname )
}
}
hello_offset += 2 + int ( noCS )
}
}
if rtype == SSL3_RT_CHANGE_CIPHER_SPEC || rtype == SSL3_RT_APPLICATION_DATA ||
clen := uint ( handshakeMsg [ hello_offset ] )
rtype == SSL3_RT_ALERT {
hello_offset ++
// fmt.Println("OTHER DATA; PASSING THRU")
passthru = true
if ! cr . client {
} else if rtype == SSL3_RT_HANDSHAKE {
fmt . Println ( "SERVER selected compression method: " , clen )
passthru = false
} else {
} else {
return errors . New ( fmt . Sprintf ( "Expected TLS server handshake byte was not received [%#x vs 0x16]" , rtype ) )
fmt . Println ( SRC , "HELLO COMPRESSION METHODS LEN = " , clen )
fmt . Println ( SRC , "HELLO COMPRESSION METHODS: " , handshakeMsg [ hello_offset : hello_offset + int ( clen ) ] )
hello_offset += int ( clen )
}
}
if passthru {
var extlen uint16 = 0
// fmt.Println("passthru writing buf again and continuing:")
conn . Write ( chunk )
if hello_offset == len ( handshakeMsg ) {
fmt . Println ( "Message didn't have any extensions present" )
} else {
extlen = binary . BigEndian . Uint16 ( handshakeMsg [ hello_offset : hello_offset + 2 ] )
fmt . Println ( SRC , "HELLO EXTENSIONS LENGTH: " , extlen )
hello_offset += 2
}
if cr . client {
ext_ctr := 0
for ext_ctr < int ( extlen ) - 2 {
exttype := binary . BigEndian . Uint16 ( handshakeMsg [ hello_offset : hello_offset + 2 ] )
hello_offset += 2
ext_ctr += 2
// fmt.Printf("PROGRESS: %v of %v, %v of %v\n", ext_ctr, extlen, hello_offset, len(handshakeMsg))
fmt . Printf ( "EXTTYPE = %#x (%s)\n" , exttype , gettlsExtensionName ( uint ( exttype ) ) )
inner_len := binary . BigEndian . Uint16 ( handshakeMsg [ hello_offset : hello_offset + 2 ] )
hello_offset += int ( inner_len ) + 2
ext_ctr += int ( inner_len ) + 2
}
} * /
other . Write ( cr . data )
continue
}
if cr . client {
other . Write ( cr . data )
continue
}
if ! cr . client && isExpected ( SSL3_MT_SERVER_HELLO , server_expected ) {
server_expected = [ ] uint { SSL3_MT_CERTIFICATE }
}
if ! cr . client && s == SSL3_MT_HELLO_REQUEST {
// fmt.Println("Server sent hello request")
/ * if server_change_cipher {
x509Valid = true
other . Write ( cr . data )
dChan <- true
dChan2 <- true
break select_loop
}
* /
other . Write ( cr . data )
continue
continue
}
}
serverMsg := chunk [ 5 : ]
if s > SSL3_MT_CERTIFICATE_STATUS {
s := serverMsg [ 0 ]
fmt . Println ( "WTF: " , cr . data )
log . Debugf ( "TLSGUARD: s = %#x\n" , s )
}
if s == SSL3_MT_CERTIFICATE {
if s == SSL3_MT_CERTIFICATE {
// Message len, 3 bytes
// fmt.Printf("chunk len = %v, handshakeMsgLen = %v, slint = %v\n", len(chunk), len(handshakeMsg), handshakeMessageLenInt)
serverMessageLen := serverMsg [ 1 : 4 ]
if len ( handshakeMsg ) < handshakeMessageLenInt {
serverMessageLenInt := int ( int ( serverMessageLen [ 0 ] ) << 16 | int ( serverMessageLen [ 1 ] ) << 8 | int ( serverMessageLen [ 2 ] ) )
return errors . New ( fmt . Sprintf ( "len(handshakeMsg) %v < handshakeMessageLenInt %v!\n" , len ( handshakeMsg ) , handshakeMessageLenInt ) )
// fmt.Printf("chunk len = %v, serverMsgLen = %v, slint = %v\n", len(chunk), len(serverMsg), serverMessageLenInt)
}
if len ( serverMsg ) < serverMessageLenInt {
serverHelloBody := handshakeMsg [ 4 : 4 + handshakeMessageLenInt ]
return errors . New ( fmt . Sprintf ( "len(serverMsg) %v < serverMessageLenInt %v!\n" , len ( serverMsg ) , serverMessageLenInt ) )
}
serverHelloBody := serverMsg [ 4 : 4 + serverMessageLenInt ]
certChainLen := int ( int ( serverHelloBody [ 0 ] ) << 16 | int ( serverHelloBody [ 1 ] ) << 8 | int ( serverHelloBody [ 2 ] ) )
certChainLen := int ( int ( serverHelloBody [ 0 ] ) << 16 | int ( serverHelloBody [ 1 ] ) << 8 | int ( serverHelloBody [ 2 ] ) )
remaining := certChainLen
remaining := certChainLen
pos := serverHelloBody [ 3 : certChainLen ]
pos := serverHelloBody [ 3 : certChainLen ]
@ -136,6 +641,7 @@ func TLSGuard(conn, conn2 net.Conn, fqdn string) error {
// var certChain []*x509.Certificate
// var certChain []*x509.Certificate
var verifyOptions x509 . VerifyOptions
var verifyOptions x509 . VerifyOptions
//fqdn = "www.reddit.com"
if fqdn != "" {
if fqdn != "" {
verifyOptions . DNSName = fqdn
verifyOptions . DNSName = fqdn
}
}
@ -162,44 +668,75 @@ func TLSGuard(conn, conn2 net.Conn, fqdn string) error {
pos = pos [ 3 + certLen : ]
pos = pos [ 3 + certLen : ]
}
}
}
}
verifyOptions . Intermediates = pool
verifyOptions . Intermediates = pool
// fmt.Println("ATTEMPTING TO VERIFY: ", fqdn)
// fmt.Println("ATTEMPTING TO VERIFY: ", fqdn)
_ , err = c . Verify ( verifyOptions )
_ , err : = c . Verify ( verifyOptions )
// fmt.Println("ATTEMPTING TO VERIFY RESULT: ", err)
// fmt.Println("ATTEMPTING TO VERIFY RESULT: ", err)
if err != nil {
if err != nil {
return err
return err
} else {
} else {
valid = true
x509Valid = true
other . Write ( cr . data )
dChan <- true
dChan2 <- true
break select_loop
}
}
// lse if s == 0x0d { fmt.Printf("found a client cert request, sending buf to client\n") }
} else if s == SSL3_MT_SERVER_DONE {
conn . Write ( chunk )
break
} else if s == SSL3_MT_CERTIFICATE_REQUEST {
break
}
}
other . Write ( cr . data )
if x509Valid || ( s == SSL3_MT_SERVER_DONE ) || ( s == SSL3_MT_CERTIFICATE_REQUEST ) {
// fmt.Println("BREAKING OUT OF LOOP 1")
dChan <- true
dChan2 <- true
// fmt.Println("BREAKING OUT OF LOOP 2")
break select_loop
}
// fmt.Printf("Sending chunk of type %d to client.\n", s)
// fmt.Printf("Sending chunk of type %d to client.\n", s)
} else if cr . err != nil {
ndone ++
conn . Write ( chunk )
if cr . client {
fmt . Println ( "Client read error: " , cr . err )
} else {
fmt . Println ( "Server read error: " , cr . err )
}
}
if ! valid {
return cr . err
return errors . New ( "Unknown error: TLS connection could not be validated" )
}
}
return nil
}
}
// fmt.Println("WAITING; ndone = ", ndone)
for ndone < 2 {
// fmt.Println("WAITING; ndone = ", ndone)
select {
case cr := <- crChan :
// fmt.Printf("CHAN DATA: %v, %v, %v\n", cr.client, cr.err, len(cr.data))
if cr . err != nil || cr . data == nil {
ndone ++
} else if cr . client {
conn2 . Write ( cr . data )
} else if ! cr . client {
conn . Write ( cr . data )
}
}
func readNBytes ( conn net . Conn , numBytes int ) ( [ ] byte , error ) {
res := make ( [ ] byte , 0 )
temp := make ( [ ] byte , 1 )
for i := 0 ; i < numBytes ; i ++ {
_ , err := io . ReadAtLeast ( conn , temp , 1 )
if err != nil {
return res , err
}
}
res = append ( res , temp [ 0 ] )
}
}
return res , nil
// fmt.Println("______ ndone = 2\n")
// dChan <- true
//close(dChan)
//close(dChan2)
if ! x509Valid {
return errors . New ( "Unknown error: TLS connection could not be validated" )
}
return nil
}
}