mirror of
https://github.com/fosrl/newt.git
synced 2026-07-12 11:15:32 -05:00
89 lines
2.8 KiB
Go
89 lines
2.8 KiB
Go
package browsergateway
|
|
|
|
import (
|
|
"encoding/asn1"
|
|
"fmt"
|
|
)
|
|
|
|
// RDCleanPath PDU version (BASE_VERSION + 1 = 3389 + 1).
|
|
const rdCleanPathVersion = int64(3390)
|
|
|
|
// rdCleanPathPdu is a Go translation of the ASN.1 SEQUENCE defined in the
|
|
// ironrdp-rdcleanpath crate. All optional fields use EXPLICIT context-specific
|
|
// tagging, matching the Rust `der::Sequence` derivation with
|
|
// `tag_mode = "EXPLICIT"`.
|
|
//
|
|
// We only need a subset of fields for the basic proxy flow, but the struct
|
|
// declares every tag we may encounter so that decoding does not fail on an
|
|
// unexpected element.
|
|
type rdCleanPathPdu struct {
|
|
Version int64 `asn1:"explicit,tag:0"`
|
|
Destination string `asn1:"explicit,tag:2,optional,utf8"`
|
|
ProxyAuth string `asn1:"explicit,tag:3,optional,utf8"`
|
|
ServerAuth string `asn1:"explicit,tag:4,optional,utf8"`
|
|
PreconnectionBlob string `asn1:"explicit,tag:5,optional,utf8"`
|
|
X224 []byte `asn1:"explicit,tag:6,optional"`
|
|
ServerCertChain [][]byte `asn1:"explicit,tag:7,optional"`
|
|
ServerAddr string `asn1:"explicit,tag:9,optional,utf8"`
|
|
}
|
|
|
|
// decodeRDCleanPathRequest parses a client-to-proxy RDCleanPath PDU.
|
|
func decodeRDCleanPathRequest(buf []byte) (*rdCleanPathPdu, error) {
|
|
var pdu rdCleanPathPdu
|
|
rest, err := asn1.Unmarshal(buf, &pdu)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("asn1 unmarshal: %w", err)
|
|
}
|
|
if len(rest) != 0 {
|
|
return nil, fmt.Errorf("trailing data after RDCleanPath PDU: %d bytes", len(rest))
|
|
}
|
|
if pdu.Version != rdCleanPathVersion {
|
|
return nil, fmt.Errorf("unexpected RDCleanPath version: %d", pdu.Version)
|
|
}
|
|
return &pdu, nil
|
|
}
|
|
|
|
// encodeRDCleanPathResponse builds a proxy-to-client RDCleanPath response PDU
|
|
// containing the server address, X.224 connection confirm and server TLS chain.
|
|
func encodeRDCleanPathResponse(serverAddr string, x224Rsp []byte, certChain [][]byte) ([]byte, error) {
|
|
pdu := rdCleanPathPdu{
|
|
Version: rdCleanPathVersion,
|
|
X224: x224Rsp,
|
|
ServerCertChain: certChain,
|
|
ServerAddr: serverAddr,
|
|
}
|
|
return asn1.Marshal(pdu)
|
|
}
|
|
|
|
// detectRDCleanPathLength returns the total DER length of an RDCleanPath PDU
|
|
// if enough bytes are available, otherwise -1.
|
|
//
|
|
// The PDU is a DER SEQUENCE, which begins with the universal SEQUENCE tag
|
|
// (0x30) followed by a length octet/octets. We parse just enough to know the
|
|
// total length so we can buffer accordingly.
|
|
func detectRDCleanPathLength(buf []byte) int {
|
|
if len(buf) < 2 {
|
|
return -1
|
|
}
|
|
if buf[0] != 0x30 {
|
|
// Not a SEQUENCE: cannot be RDCleanPath.
|
|
return -2
|
|
}
|
|
l := buf[1]
|
|
if l < 0x80 {
|
|
return 2 + int(l)
|
|
}
|
|
n := int(l & 0x7f)
|
|
if n == 0 || n > 4 {
|
|
return -2
|
|
}
|
|
if len(buf) < 2+n {
|
|
return -1
|
|
}
|
|
total := 0
|
|
for i := 0; i < n; i++ {
|
|
total = (total << 8) | int(buf[2+i])
|
|
}
|
|
return 2 + n + total
|
|
}
|