Skip to content

Commit

Permalink
feat(server): support tdesktop
Browse files Browse the repository at this point in the history
Initial support for tdesktop key exchange.

Fix #829
  • Loading branch information
ernado committed Aug 14, 2022
1 parent d28a749 commit 1d5ccae
Show file tree
Hide file tree
Showing 15 changed files with 552 additions and 11 deletions.
2 changes: 2 additions & 0 deletions internal/_schema/schema.tl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ resPQ#05162463 nonce:int128 server_nonce:int128 pq:bytes server_public_key_finge

p_q_inner_data#83c95aec pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
p_q_inner_data_dc#a9f55f95 pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
p_q_inner_data_temp_dc#56fddf88 pq:bytes p:bytes q:bytes nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;


server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:bytes = Server_DH_Params;
Expand Down
85 changes: 75 additions & 10 deletions internal/exchange/server_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,60 @@ func serverError(code int32, err error) error {
}
}

// req_pq#60469778 or req_pq_multi#be7e8ef1
type reqPQ struct {
Type uint32
Nonce bin.Int128
}

func (r *reqPQ) Decode(b *bin.Buffer) error {
var (
legacy mt.ReqPqRequest
multi mt.ReqPqMultiRequest
)
id, err := b.PeekID()
if err != nil {
return err
}
r.Type = id
switch id {
case legacy.TypeID():
if err := legacy.Decode(b); err != nil {
return err
}
r.Nonce = legacy.Nonce
return nil
case multi.TypeID():
if err := multi.Decode(b); err != nil {
return err
}
r.Nonce = multi.Nonce
return nil
default:
return bin.NewUnexpectedID(id)
}
}

type reqOrDH struct {
Type uint32
DH mt.ReqDHParamsRequest
Req reqPQ
}

func (r *reqOrDH) Decode(b *bin.Buffer) error {
id, err := b.PeekID()
if err != nil {
return err
}
r.Type = id
switch id {
case r.DH.TypeID():
return r.DH.Decode(b)
default:
return r.Req.Decode(b)
}
}

// Run runs server-side flow.
// If b parameter is not nil, it will be used as first read message.
// Otherwise, it will be read from connection.
Expand All @@ -46,11 +100,11 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
}

// 1. Client sends query to server
//
// req_pq#60469778 nonce:int128 = ResPQ; // legacy
// req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;
var pqReq mt.ReqPqMultiRequest
var req reqPQ
b := new(bin.Buffer)
if err := s.readUnencrypted(ctx, b, &pqReq); err != nil {
if err := s.readUnencrypted(ctx, b, &req); err != nil {
return ServerExchangeResult{}, err
}
s.log.Debug("Received client ReqPqMultiRequest")
Expand All @@ -68,10 +122,11 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
return ServerExchangeResult{}, errors.Wrap(err, "generate pq")
}

SendResPQ:
s.log.Debug("Sending ResPQ", zap.String("pq", pq.String()))
if err := s.writeUnencrypted(ctx, b, &mt.ResPQ{
Pq: pq.Bytes(),
Nonce: pqReq.Nonce,
Nonce: req.Nonce,
ServerNonce: serverNonce,
ServerPublicKeyFingerprints: []int64{
s.key.Fingerprint(),
Expand All @@ -84,15 +139,25 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
//
// req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string
// q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params
var dhParams mt.ReqDHParamsRequest
var dhParams reqOrDH
if err := s.readUnencrypted(ctx, b, &dhParams); err != nil {
return ServerExchangeResult{}, err
}
s.log.Debug("Received client ReqDHParamsRequest")
switch dhParams.Type {
case mt.ReqPqRequestTypeID, mt.ReqPqMultiRequestTypeID:
// Client can send fake req_pq on start. Ignore it.
//
// Next one should be not fake.
s.log.Debug("Received ReqPQ again")
req = dhParams.Req
goto SendResPQ
default:
s.log.Debug("Received client ReqDHParamsRequest")
}

var innerData mt.PQInnerData
{
r, err := crypto.DecodeRSAPad(dhParams.EncryptedData, s.key.RSA)
r, err := crypto.DecodeRSAPad(dhParams.DH.EncryptedData, s.key.RSA)
if err != nil {
return ServerExchangeResult{}, wrapKeyNotFound(err)
}
Expand Down Expand Up @@ -133,7 +198,7 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
}

data := mt.ServerDHInnerData{
Nonce: pqReq.Nonce,
Nonce: req.Nonce,
ServerNonce: serverNonce,
G: g,
GA: ga.Bytes(),
Expand All @@ -155,7 +220,7 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
s.log.Debug("Sending ServerDHParamsOk", zap.Int("g", g))
// 5. Server responds with Server_DH_Params.
if err := s.writeUnencrypted(ctx, b, &mt.ServerDHParamsOk{
Nonce: pqReq.Nonce,
Nonce: req.Nonce,
ServerNonce: serverNonce,
EncryptedAnswer: answer,
}); err != nil {
Expand Down Expand Up @@ -193,7 +258,7 @@ func (s ServerExchange) Run(ctx context.Context) (ServerExchangeResult, error) {
// new_nonce_hash1:int128 = Set_client_DH_params_answer;
s.log.Debug("Sending DhGenOk")
if err := s.writeUnencrypted(ctx, b, &mt.DhGenOk{
Nonce: pqReq.Nonce,
Nonce: req.Nonce,
ServerNonce: serverNonce,
NewNonceHash1: crypto.NonceHash1(innerData.NewNonce, authKey),
}); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/generate.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package internal

//go:generate go run github.com/gotd/td/cmd/gotdgen --clean --package mt --target mt --client=false --schema _schema/schema.tl
//go:generate go run github.com/gotd/td/cmd/gotdgen --clean --package mt --target mt --schema _schema/schema.tl
54 changes: 54 additions & 0 deletions internal/mt/tl_client_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions internal/mt/tl_destroy_session_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions internal/mt/tl_get_future_salts_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1d5ccae

Please sign in to comment.