Skip to content

Commit e12ef60

Browse files
Surya Ahujameta-codesync[bot]
authored andcommitted
modify crypter to obfuscate only for non tls connections
Reviewed By: shringiarpit26 Differential Revision: D82873725 fbshipit-source-id: 86d7d581d51b4e261b7748275a6443989340b06e
1 parent e9dd668 commit e12ef60

File tree

4 files changed

+848
-24
lines changed

4 files changed

+848
-24
lines changed

client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func SetClientDialer(network, address string, secret []byte) ClientOption {
2929
if err != nil {
3030
return err
3131
}
32-
c.crypter = newCrypter(secret, conn, false)
32+
c.crypter = newCrypter(secret, conn, false, false)
3333
return nil
3434
}
3535
}
@@ -39,7 +39,7 @@ func SetClientDialer(network, address string, secret []byte) ClientOption {
3939
// A secret for the connection must also be provided.
4040
func SetClientWithConn(conn *net.TCPConn, secret []byte) ClientOption {
4141
return func(c *Client) error {
42-
c.crypter = newCrypter(secret, conn, false)
42+
c.crypter = newCrypter(secret, conn, false, false)
4343
return nil
4444
}
4545
}
@@ -64,7 +64,7 @@ func SetClientDialerWithLocalAddr(network, raddr, laddr string, secret []byte) C
6464
if err != nil {
6565
return err
6666
}
67-
c.crypter = newCrypter(secret, conn, false)
67+
c.crypter = newCrypter(secret, conn, false, false)
6868
return nil
6969
}
7070
}

crypt.go

Lines changed: 99 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ func crypt(secret []byte, p *Packet) error {
8989
}
9090

9191
// newCrypter makes a new crypter
92-
func newCrypter(secret []byte, c net.Conn, proxy bool) *crypter {
93-
return &crypter{secret: secret, Conn: c, Reader: bufio.NewReaderSize(c, 107), proxy: proxy}
92+
func newCrypter(secret []byte, c net.Conn, proxy, tls bool) *crypter {
93+
return &crypter{secret: secret, Conn: c, Reader: bufio.NewReaderSize(c, 107), proxy: proxy, tls: tls}
9494
}
9595

9696
// crypter wraps the net.Conn and performs reads and writes and crypt ops
@@ -106,6 +106,10 @@ type crypter struct {
106106
secret []byte
107107
// proxy if set, will strip the ha-proxy style ascii header
108108
proxy bool
109+
110+
// setting the tls parameters enables RFC 9887 specific handling
111+
// within the crypter
112+
tls bool
109113
}
110114

111115
// read will read a packet from the underlying net.Conn and decyrpt it
@@ -154,22 +158,43 @@ func (c *crypter) read() (*Packet, error) {
154158
crypterUnmarshalError.Inc()
155159
return nil, err
156160
}
157-
// run crypt first before we look for bad secrets
158-
if err := crypt(c.secret, &p); err != nil {
159-
crypterCryptError.Inc()
160-
return nil, err
161-
}
162-
// if err is != nil, we hit a bug
163-
// if reply is != nil, we found a bad secret.
164-
// if both are non nil, we only inspect the error as that
165-
// is a higher error condition in the server than a bad secret is
166-
if reply, err := c.detectBadSecret(&p); err != nil {
167-
return nil, err
168-
} else if reply != nil {
169-
if _, err := c.write(reply); err != nil {
170-
return nil, fmt.Errorf("bad secret, crypt write fail for ip [%s]: %v", c.RemoteAddr().String(), err)
161+
162+
if !c.tls {
163+
// obfuscation mechanism only applies to non-tls connections
164+
// run crypt first before we look for bad secrets
165+
if err := crypt(c.secret, &p); err != nil {
166+
crypterCryptError.Inc()
167+
return nil, err
168+
}
169+
// if err is != nil, we hit a bug
170+
// if reply is != nil, we found a bad secret.
171+
// if both are non nil, we only inspect the error as that
172+
// is a higher error condition in the server than a bad secret is
173+
if reply, err := c.detectBadSecret(&p); err != nil {
174+
return nil, err
175+
} else if reply != nil {
176+
if _, err := c.write(reply); err != nil {
177+
return nil, fmt.Errorf("bad secret, crypt write fail for ip [%s]: %w", c.RemoteAddr().String(), err)
178+
}
179+
return nil, fmt.Errorf("bad secret detected for ip [%s]", c.RemoteAddr().String())
180+
}
181+
} else {
182+
/*
183+
A TLS TACACS+ server that receives a packet with the TAC_PLUS_UNENCRYPTED_FLAG bit
184+
not set to 1 over a TLS connection, MUST return an error of TAC_PLUS_AUTHEN_STATUS_ERROR,
185+
TAC_PLUS_AUTHOR_STATUS_ERROR, or TAC_PLUS_ACCT_STATUS_ERROR as appropriate for the
186+
TACACS+ message type, with the TAC_PLUS_UNENCRYPTED_FLAG bit set to 1, and terminate the session
187+
*/
188+
if !p.Header.Flags.Has(UnencryptedFlag) {
189+
reply, err := c.unsetFlagReply(p.Header)
190+
if err != nil {
191+
return nil, err
192+
}
193+
if _, err := c.write(reply); err != nil {
194+
return nil, fmt.Errorf("unencrypted flag not set, crypt write fail for ip [%s]: %w", c.RemoteAddr().String(), err)
195+
}
196+
return nil, fmt.Errorf("unencrypted flag not set for ip [%s]", c.RemoteAddr().String())
171197
}
172-
return nil, fmt.Errorf("bad secret detected for ip [%s]", c.RemoteAddr().String())
173198
}
174199

175200
crypterRead.Inc()
@@ -185,10 +210,17 @@ func (c *crypter) write(p *Packet) (int, error) {
185210
return 0, fmt.Errorf("handler error, packet.Body cannot be nil")
186211
}
187212
p.Header.Length = uint32(len(p.Body))
188-
if err := crypt(c.secret, p); err != nil {
189-
crypterCryptError.Inc()
190-
return 0, err
213+
if !c.tls {
214+
if err := crypt(c.secret, p); err != nil {
215+
crypterCryptError.Inc()
216+
return 0, err
217+
}
218+
} else {
219+
// before we marshal, we need to set the unencrypted flag
220+
// on packets when tls is enabled
221+
p.Header.Flags.Set(UnencryptedFlag)
191222
}
223+
192224
b, err := p.MarshalBinary()
193225
if err != nil {
194226
crypterMarshalError.Inc()
@@ -266,6 +298,53 @@ func (c crypter) detectBadSecret(p *Packet) (*Packet, error) {
266298
return nil, nil
267299
}
268300

301+
func (c crypter) unsetFlagReply(h *Header) (*Packet, error) {
302+
var b []byte
303+
var err error
304+
switch h.Type {
305+
case Authenticate:
306+
b, err = NewAuthenReply(
307+
SetAuthenReplyStatus(AuthenStatusError),
308+
SetAuthenReplyServerMsg("unencrypted flag not set"),
309+
).MarshalBinary()
310+
if err != nil {
311+
crypterMarshalError.Inc()
312+
return nil, err
313+
}
314+
case Authorize:
315+
b, err = NewAuthorReply(
316+
SetAuthorReplyStatus(AuthorStatusError),
317+
SetAuthorReplyServerMsg("unencrypted flag not set"),
318+
).MarshalBinary()
319+
if err != nil {
320+
crypterMarshalError.Inc()
321+
return nil, err
322+
}
323+
case Accounting:
324+
b, err = NewAcctReply(
325+
SetAcctReplyStatus(AcctReplyStatusError),
326+
SetAcctReplyServerMsg("unencrypted flag not set"),
327+
).MarshalBinary()
328+
if err != nil {
329+
crypterMarshalError.Inc()
330+
return nil, err
331+
}
332+
default:
333+
return nil, fmt.Errorf("unknown header type [%v]", h.Type)
334+
}
335+
// reset some flags and state for this error reply.
336+
// under error conditions it can be common in the rfc to reset the sequence to 1
337+
// if the error is particularly egregious. an unset encrypted flag on a TLS connection seems like it fits and
338+
// the rfc is unclear for this particular condition on what to do
339+
h.SeqNo = SequenceNumber(1)
340+
h.Flags.Set(UnencryptedFlag)
341+
342+
return NewPacket(
343+
SetPacketHeader(h),
344+
SetPacketBody(b),
345+
), nil
346+
}
347+
269348
func (c crypter) badSecretReply(h *Header) (*Packet, error) {
270349
var b []byte
271350
var err error

0 commit comments

Comments
 (0)