mirror of
				https://gogs.blitter.com/RLabs/xs
				synced 2024-08-14 10:26:42 +00:00 
			
		
		
		
	xsd: Added -aK,-aC,-aH to control accepted client proposals
This commit is contained in:
		
							parent
							
								
									34399dd907
								
							
						
					
					
						commit
						ff57630342
					
				
					 4 changed files with 199 additions and 20 deletions
				
			
		
							
								
								
									
										21
									
								
								xs/xs.go
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								xs/xs.go
									
										
									
									
									
								
							|  | @ -34,9 +34,9 @@ import ( | |||
| 	_ "net/http/pprof" | ||||
| 
 | ||||
| 	xs "blitter.com/go/xs" | ||||
| 	"blitter.com/go/xs/xsnet" | ||||
| 	"blitter.com/go/xs/logger" | ||||
| 	"blitter.com/go/xs/spinsult" | ||||
| 	"blitter.com/go/xs/xsnet" | ||||
| 	isatty "github.com/mattn/go-isatty" | ||||
| ) | ||||
| 
 | ||||
|  | @ -821,23 +821,25 @@ func main() { | |||
| 			cmdStr = string(copySrc) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	proto := "tcp" | ||||
| 	if kcpMode != "unused" { | ||||
| 			proto = "kcp" | ||||
| 		proto = "kcp" | ||||
| 	} | ||||
| 	conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		exitWithStatus(3) | ||||
| 	} | ||||
| 	defer conn.Close() // nolint: errcheck | ||||
| 	// From this point on, conn is a secure encrypted channel | ||||
| 
 | ||||
| 	// Set stdin in raw mode if it's an interactive session | ||||
| 	// TODO: send flag to server side indicating this | ||||
| 	//  affects shell command used | ||||
| 	var oldState *xs.State | ||||
| 	defer conn.Close() // nolint: errcheck | ||||
| 
 | ||||
| 	// From this point on, conn is a secure encrypted channel | ||||
| 
 | ||||
| 	if shellMode { | ||||
| 		if isatty.IsTerminal(os.Stdin.Fd()) { | ||||
| 			oldState, err = xs.MakeRaw(int(os.Stdin.Fd())) | ||||
|  | @ -869,7 +871,11 @@ func main() { | |||
| 	rec := xs.NewSession(op, []byte(uname), []byte(remoteHost), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0) | ||||
| 	sendErr := sendSessionParams(&conn, rec) | ||||
| 	if sendErr != nil { | ||||
| 		log.Fatal(sendErr) | ||||
| 		_ = xs.Restore(int(os.Stdin.Fd()), oldState) // nolint: errcheck,gosec | ||||
| 		rec.SetStatus(254) | ||||
| 		fmt.Fprintln(os.Stderr, "Error: server rejected secure proposal params") // nolint: errcheck | ||||
| 		exitWithStatus(int(rec.Status())) | ||||
| 		//log.Fatal(sendErr) | ||||
| 	} | ||||
| 
 | ||||
| 	//Security scrub | ||||
|  | @ -924,13 +930,14 @@ func main() { | |||
| 		} | ||||
| 
 | ||||
| 		if rec.Status() != 0 { | ||||
| 			_ = xs.Restore(int(os.Stdin.Fd()), oldState)                     // nolint: errcheck,gosec | ||||
| 			_ = xs.Restore(int(os.Stdin.Fd()), oldState)                         // nolint: errcheck,gosec | ||||
| 			fmt.Fprintln(os.Stderr, "Session exited with status:", rec.Status()) // nolint: errcheck | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if oldState != nil { | ||||
| 		_ = xs.Restore(int(os.Stdin.Fd()), oldState) // nolint: gosec | ||||
| 		oldState = nil | ||||
| 	} | ||||
| 
 | ||||
| 	exitWithStatus(int(rec.Status())) | ||||
|  |  | |||
							
								
								
									
										107
									
								
								xsd/xsd.go
									
										
									
									
									
								
							
							
						
						
									
										107
									
								
								xsd/xsd.go
									
										
									
									
									
								
							|  | @ -23,14 +23,15 @@ import ( | |||
| 	"os/signal" | ||||
| 	"os/user" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| 	"unsafe" | ||||
| 
 | ||||
| 	"blitter.com/go/goutmp" | ||||
| 	xs "blitter.com/go/xs" | ||||
| 	"blitter.com/go/xs/xsnet" | ||||
| 	"blitter.com/go/xs/logger" | ||||
| 	"blitter.com/go/xs/xsnet" | ||||
| 	"github.com/kr/pty" | ||||
| ) | ||||
| 
 | ||||
|  | @ -429,9 +430,73 @@ func GenAuthToken(who string, connhost string) string { | |||
| 	return fmt.Sprintf("%s:%s", tokenA, hex.EncodeToString(tokenB)) | ||||
| } | ||||
| 
 | ||||
| // Demo of a simple server that listens and spawns goroutines for each | ||||
| // connecting client. Note this code is identical to standard tcp | ||||
| // server code, save for declaring 'xsnet' rather than 'net' | ||||
| var ( | ||||
| 	aKEXAlgs    allowedKEXAlgs | ||||
| 	aCipherAlgs allowedCipherAlgs | ||||
| 	aHMACAlgs   allowedHMACAlgs | ||||
| ) | ||||
| 
 | ||||
| type allowedKEXAlgs []string    // TODO | ||||
| type allowedCipherAlgs []string // TODO | ||||
| type allowedHMACAlgs []string   // TODO | ||||
| 
 | ||||
| func (a allowedKEXAlgs) allowed(k xsnet.KEXAlg) bool { | ||||
| 	for i := 0; i < len(a); i++ { | ||||
| 		if a[i] == "KEX_all" || a[i] == k.String() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (a *allowedKEXAlgs) String() string { | ||||
| 	return fmt.Sprintf("allowedKEXAlgs: %v", *a) | ||||
| } | ||||
| 
 | ||||
| func (a *allowedKEXAlgs) Set(value string) error { | ||||
| 	*a = append(*a, strings.TrimSpace(value)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (a allowedCipherAlgs) allowed(c xsnet.CSCipherAlg) bool { | ||||
| 	for i := 0; i < len(a); i++ { | ||||
| 		if a[i] == "C_all" || a[i] == c.String() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (a *allowedCipherAlgs) String() string { | ||||
| 	return fmt.Sprintf("allowedCipherAlgs: %v", *a) | ||||
| } | ||||
| 
 | ||||
| func (a *allowedCipherAlgs) Set(value string) error { | ||||
| 	*a = append(*a, strings.TrimSpace(value)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (a allowedHMACAlgs) allowed(h xsnet.CSHmacAlg) bool { | ||||
| 	for i := 0; i < len(a); i++ { | ||||
| 		if a[i] == "H_all" || a[i] == h.String() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (a *allowedHMACAlgs) String() string { | ||||
| 	return fmt.Sprintf("allowedHMACAlgs: %v", *a) | ||||
| } | ||||
| 
 | ||||
| func (a *allowedHMACAlgs) Set(value string) error { | ||||
| 	*a = append(*a, strings.TrimSpace(value)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Main server that listens and spawns goroutines for each | ||||
| // connecting client. Note this code is mostly identical to standard | ||||
| // tcp server code, save for declaring 'xsnet' rather than 'net' | ||||
| // Listener and Conns. The KEx and encrypt/decrypt is done within the type. | ||||
| // Compare to 'serverp.go' in this directory to see the equivalence. | ||||
| // TODO: reduce gocyclo | ||||
|  | @ -453,6 +518,11 @@ func main() { | |||
| 	flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max (msecs)") | ||||
| 	flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max (bytes)") | ||||
| 	flag.BoolVar(&dbg, "d", false, "debug logging") | ||||
| 
 | ||||
| 	flag.Var(&aKEXAlgs, "aK", `List of allowed KEX algs (eg. 'KEXAlgA KEXAlgB ... KEXAlgN') (default allow all)`) | ||||
| 	flag.Var(&aCipherAlgs, "aC", `List of allowed ciphers (eg. 'CipherAlgA CipherAlgB ... CipherAlgN') (default allow all)`) | ||||
| 	flag.Var(&aHMACAlgs, "aH", `List of allowed HMACs (eg. 'HMACAlgA HMACAlgB ... HMACAlgN') (default allow all)`) | ||||
| 
 | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	if vopt { | ||||
|  | @ -486,6 +556,22 @@ func main() { | |||
| 		log.SetOutput(ioutil.Discard) | ||||
| 	} | ||||
| 
 | ||||
| 	// Set up allowed algs, if specified (default allow all) | ||||
| 	if len(aKEXAlgs) == 0 { | ||||
| 		aKEXAlgs = []string{"KEX_all"} | ||||
| 	} | ||||
| 	logger.LogNotice(fmt.Sprintf("Allowed KEXAlgs: %v\n", aKEXAlgs)) // nolint: gosec,errcheck | ||||
| 
 | ||||
| 	if len(aCipherAlgs) == 0 { | ||||
| 		aCipherAlgs = []string{"C_all"} | ||||
| 	} | ||||
| 	logger.LogNotice(fmt.Sprintf("Allowed CipherAlgs: %v\n", aCipherAlgs)) // nolint: gosec,errcheck | ||||
| 
 | ||||
| 	if len(aHMACAlgs) == 0 { | ||||
| 		aHMACAlgs = []string{"H_all"} | ||||
| 	} | ||||
| 	logger.LogNotice(fmt.Sprintf("Allowed HMACAlgs: %v\n", aHMACAlgs)) // nolint: gosec,errcheck | ||||
| 
 | ||||
| 	// Set up handler for daemon signalling | ||||
| 	exitCh := make(chan os.Signal, 1) | ||||
| 	signal.Notify(exitCh, os.Signal(syscall.SIGTERM), os.Signal(syscall.SIGINT), os.Signal(syscall.SIGHUP), os.Signal(syscall.SIGUSR1), os.Signal(syscall.SIGUSR2)) | ||||
|  | @ -522,9 +608,22 @@ func main() { | |||
| 	log.Println("Serving on", laddr) | ||||
| 	for { | ||||
| 		// Wait for a connection. | ||||
| 		// Then check if client-proposed algs are allowed | ||||
| 		conn, err := l.Accept() | ||||
| 		if err != nil { | ||||
| 			log.Printf("Accept() got error(%v), hanging up.\n", err) | ||||
| 		} else if !aKEXAlgs.allowed(conn.KEX()) { | ||||
| 			log.Printf("Accept() rejected for banned KEX alg %d, hanging up.\n", conn.KEX()) | ||||
| 			conn.SetStatus(xsnet.CSEKEXAlgDenied) | ||||
| 			conn.Close() | ||||
| 		} else if !aCipherAlgs.allowed(conn.CAlg()) { | ||||
| 			log.Printf("Accept() rejected for banned Cipher alg %d, hanging up.\n", conn.CAlg()) | ||||
| 			conn.SetStatus(xsnet.CSECipherAlgDenied) | ||||
| 			conn.Close() | ||||
| 		} else if !aHMACAlgs.allowed(conn.HAlg()) { | ||||
| 			log.Printf("Accept() rejected for banned HMAC alg %d, hanging up.\n", conn.HAlg()) | ||||
| 			conn.SetStatus(xsnet.CSEHMACAlgDenied) | ||||
| 			conn.Close() | ||||
| 		} else { | ||||
| 			log.Println("Accepted client") | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ const ( | |||
| 	KEX_NEWHOPE_SIMPLE // 'NewHopeLP-Simple' - https://eprint.iacr.org/2016/1157 | ||||
| 	KEX_resvd14 | ||||
| 	KEX_resvd15 | ||||
| 	KEX_invalid = 255 | ||||
| ) | ||||
| 
 | ||||
| // Sent from client to server in order to specify which | ||||
|  | @ -38,12 +39,15 @@ type KEXAlg uint8 | |||
| // Extended exit status codes - indicate comm/pty issues | ||||
| // rather than remote end normal UNIX exit codes | ||||
| const ( | ||||
| 	CSENone           = 1024 + iota | ||||
| 	CSETruncCSO       // No CSOExitStatus in payload | ||||
| 	CSEStillOpen      // Channel closed unexpectedly | ||||
| 	CSEExecFail       // cmd.Start() (exec) failed | ||||
| 	CSEPtyExecFail    // pty.Start() (exec w/pty) failed | ||||
| 	CSEPtyGetNameFail // failed to obtain pty name | ||||
| 	CSENone            = 1024 + iota | ||||
| 	CSETruncCSO        // No CSOExitStatus in payload | ||||
| 	CSEStillOpen       // Channel closed unexpectedly | ||||
| 	CSEExecFail        // cmd.Start() (exec) failed | ||||
| 	CSEPtyExecFail     // pty.Start() (exec w/pty) failed | ||||
| 	CSEPtyGetNameFail  // failed to obtain pty name | ||||
| 	CSEKEXAlgDenied    // server rejected proposed KEX alg | ||||
| 	CSECipherAlgDenied // server rejected proposed Cipher alg | ||||
| 	CSEHMACAlgDenied   // server rejected proposed HMAC alg | ||||
| ) | ||||
| 
 | ||||
| // Extended (>255 UNIX exit status) codes | ||||
|  |  | |||
							
								
								
									
										75
									
								
								xsnet/net.go
									
										
									
									
									
								
							
							
						
						
									
										75
									
								
								xsnet/net.go
									
										
									
									
									
								
							|  | @ -70,9 +70,10 @@ type ( | |||
| 
 | ||||
| 	// Conn is a connection wrapping net.Conn with KEX & session state | ||||
| 	Conn struct { | ||||
| 		kex KEXAlg      // KEX/KEM proposal (client -> server) | ||||
| 		m   *sync.Mutex // (internal) | ||||
| 		c   *net.Conn   // which also implements io.Reader, io.Writer, ... | ||||
| 		kex KEXAlg // KEX/KEM proposal (client -> server) | ||||
| 
 | ||||
| 		m *sync.Mutex // (internal) | ||||
| 		c *net.Conn   // which also implements io.Reader, io.Writer, ... | ||||
| 
 | ||||
| 		logCipherText  bool // somewhat expensive, for debugging | ||||
| 		logPlainText   bool // INSECURE and somewhat expensive, for debugging | ||||
|  | @ -105,6 +106,67 @@ func (t *TunEndpoint) String() string { | |||
| 	return fmt.Sprintf("[%d:%s:%d]", t.Lport, t.Peer, t.Rport) | ||||
| } | ||||
| 
 | ||||
| func (k *KEXAlg) String() string { | ||||
| 	switch *k { | ||||
| 	case KEX_HERRADURA256: | ||||
| 		return "KEX_HERRADURA256" | ||||
| 	case KEX_HERRADURA512: | ||||
| 		return "KEX_HERRADURA512" | ||||
| 	case KEX_HERRADURA1024: | ||||
| 		return "KEX_HERRADURA1024" | ||||
| 	case KEX_HERRADURA2048: | ||||
| 		return "KEX_HERRADURA2048" | ||||
| 	case KEX_KYBER512: | ||||
| 		return "KEX_KYBER512" | ||||
| 	case KEX_KYBER768: | ||||
| 		return "KEX_KYBER768" | ||||
| 	case KEX_KYBER1024: | ||||
| 		return "KEX_KYBER1024" | ||||
| 	case KEX_NEWHOPE: | ||||
| 		return "KEX_NEWHOPE" | ||||
| 	case KEX_NEWHOPE_SIMPLE: | ||||
| 		return "KEX_NEWHOPE_SIMPLE" | ||||
| 	default: | ||||
| 		return "KEX_ERR_UNK" | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (hc *Conn) CAlg() CSCipherAlg { | ||||
| 	return CSCipherAlg(hc.cipheropts & 0x0FF) | ||||
| } | ||||
| 
 | ||||
| func (c *CSCipherAlg) String() string { | ||||
| 	switch *c & 0x0FF { | ||||
| 	case CAlgAES256: | ||||
| 		return "C_AES_256" | ||||
| 	case CAlgTwofish128: | ||||
| 		return "C_TWOFISH_128" | ||||
| 	case CAlgBlowfish64: | ||||
| 		return "C_BLOWFISH_64" | ||||
| 	case CAlgCryptMT1: | ||||
| 		return "C_CRYPTMT1" | ||||
| 	case CAlgWanderer: | ||||
| 		return "C_WANDERER" | ||||
| 	default: | ||||
| 		return "C_ERR_UNK" | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (hc *Conn) HAlg() CSHmacAlg { | ||||
| 	return CSHmacAlg((hc.cipheropts >> 8) & 0x0FF) | ||||
| } | ||||
| 
 | ||||
| func (h *CSHmacAlg) String() string { | ||||
| 	switch (*h >> 8) & 0x0FF { | ||||
| 	case HmacSHA256: | ||||
| 		return "H_SHA256" | ||||
| 	case HmacSHA512: | ||||
| 		return "C_SHA512" | ||||
| 	default: | ||||
| 		return "H_ERR_UNK" | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func _initLogging(d bool, c string, f logger.Priority) { | ||||
| 	if Log == nil { | ||||
| 		Log, _ = logger.New(f, fmt.Sprintf("%s:xsnet", c)) | ||||
|  | @ -129,6 +191,10 @@ func (hc *Conn) Unlock() { | |||
| 	hc.m.Unlock() | ||||
| } | ||||
| 
 | ||||
| func (hc Conn) KEX() KEXAlg { | ||||
| 	return hc.kex | ||||
| } | ||||
| 
 | ||||
| func (hc Conn) GetStatus() CSOType { | ||||
| 	return *hc.closeStat | ||||
| } | ||||
|  | @ -935,6 +1001,9 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { | |||
| 	default: | ||||
| 		return Conn{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Finally, ensure alg proposed by client is allowed by server config | ||||
| 	//if hc.kex.String() { | ||||
| 	log.Println("[hc.Accept successful]") | ||||
| 	return | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue