nex-go/hpp_packet.go
2024-02-11 16:58:22 -05:00

153 lines
3.5 KiB
Go

package nex
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
)
// HPPPacket holds all the data about an HPP request
type HPPPacket struct {
sender *HPPClient
accessKeySignature []byte
passwordSignature []byte
payload []byte
message *RMCMessage
processed chan bool
}
// Sender returns the Client who sent the packet
func (p *HPPPacket) Sender() ConnectionInterface {
return p.sender
}
// Payload returns the packets payload
func (p *HPPPacket) Payload() []byte {
return p.payload
}
// SetPayload sets the packets payload
func (p *HPPPacket) SetPayload(payload []byte) {
p.payload = payload
}
func (p *HPPPacket) validateAccessKeySignature(signature string) error {
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("Failed to decode access key signature. %s", err)
}
p.accessKeySignature = signatureBytes
calculatedSignature, err := p.calculateAccessKeySignature()
if err != nil {
return fmt.Errorf("Failed to calculate access key signature. %s", err)
}
if !bytes.Equal(calculatedSignature, p.accessKeySignature) {
return errors.New("Access key signature does not match")
}
return nil
}
func (p *HPPPacket) calculateAccessKeySignature() ([]byte, error) {
accessKey := p.Sender().Endpoint().AccessKey()
accessKeyBytes, err := hex.DecodeString(accessKey)
if err != nil {
return nil, err
}
signature, err := p.calculateSignature(p.payload, accessKeyBytes)
if err != nil {
return nil, err
}
return signature, nil
}
func (p *HPPPacket) validatePasswordSignature(signature string) error {
signatureBytes, err := hex.DecodeString(signature)
if err != nil {
return fmt.Errorf("Failed to decode password signature. %s", err)
}
p.passwordSignature = signatureBytes
calculatedSignature, err := p.calculatePasswordSignature()
if err != nil {
return fmt.Errorf("Failed to calculate password signature. %s", err)
}
if !bytes.Equal(calculatedSignature, p.passwordSignature) {
return errors.New("Password signature does not match")
}
return nil
}
func (p *HPPPacket) calculatePasswordSignature() ([]byte, error) {
sender := p.Sender()
pid := sender.PID()
account, _ := sender.Endpoint().(*HPPServer).AccountDetailsByPID(pid)
if account == nil {
return nil, errors.New("PID does not exist")
}
key := DeriveKerberosKey(pid, []byte(account.Password))
signature, err := p.calculateSignature(p.payload, key)
if err != nil {
return nil, err
}
return signature, nil
}
func (p *HPPPacket) calculateSignature(buffer []byte, key []byte) ([]byte, error) {
mac := hmac.New(md5.New, key)
_, err := mac.Write(buffer)
if err != nil {
return nil, err
}
hmac := mac.Sum(nil)
return hmac, nil
}
// RMCMessage returns the packets RMC Message
func (p *HPPPacket) RMCMessage() *RMCMessage {
return p.message
}
// SetRMCMessage sets the packets RMC Message
func (p *HPPPacket) SetRMCMessage(message *RMCMessage) {
p.message = message
}
// NewHPPPacket creates and returns a new HPPPacket using the provided Client and payload
func NewHPPPacket(client *HPPClient, payload []byte) (*HPPPacket, error) {
hppPacket := &HPPPacket{
sender: client,
payload: payload,
processed: make(chan bool),
}
if payload != nil {
rmcMessage := NewRMCRequest(client.Endpoint())
err := rmcMessage.FromBytes(payload)
if err != nil {
return nil, fmt.Errorf("Failed to decode HPP request. %s", err)
}
hppPacket.SetRMCMessage(rmcMessage)
}
return hppPacket, nil
}