From 4925f96003412f7b8e41ea1047ae26ea8a96ba6f Mon Sep 17 00:00:00 2001 From: zengl Date: Wed, 4 Sep 2024 23:01:58 +0800 Subject: [PATCH] update code structure and symbols to be more self-explanatory. # Conflicts: # ac/config.go # ac/main/main.go # ac/msghandler.go # ac/udpac.go # agent/config.go # agent/knock.go # agent/main/export.go # agent/main/main.go # agent/msghandler.go # agent/request.go # agent/udpagent.go # core/benchmark/ecc_rsa_test.go # core/initiator.go # core/responder.go # nhp/packet.go # server/config.go # server/main/main.go # server/msghandler.go # server/nhpauth.go # server/udpserver.go # test/ecdh_test.go # test/ecdsa_test.go # test/packet_test.go # test/toml_test.go --- Makefile | 9 +- ac/config.go | 36 +-- ac/main/main.go | 14 +- ac/msghandler.go | 82 +++-- ac/readme.md | 12 +- ac/{udpdoor.go => udpac.go} | 124 +++---- agent/config.go | 8 +- agent/knock.go | 50 +-- agent/main/export.go | 20 +- agent/main/main.go | 14 +- agent/msghandler.go | 8 +- agent/request.go | 30 +- agent/udpagent.go | 80 ++--- build.bat | 11 + common/errors.go | 13 +- {nhp => core}/benchmark/ecc_rsa_test.go | 56 ++-- {nhp => core}/benchmark/rsa_utils.go | 0 {nhp => core}/constants.go | 2 +- core/crypto.go | 242 ++++++++++++++ {nhp => core}/device.go | 151 ++++++--- core/errors.go | 113 +++++++ {nhp => core}/initiator.go | 179 ++++++---- {nhp => core}/kdf.go | 2 +- core/main/main.go | 7 + core/main/nhpdevice.go | 320 ++++++++++++++++++ core/main/nhpdevicedef.h | 137 ++++++++ core/packet.go | 224 +++++++++++++ {nhp => core}/peer.go | 2 +- {nhp => core}/readme.md | 4 +- {nhp => core}/responder.go | 255 ++++++++++----- core/scheme/curve/curve.go | 93 ++++++ core/scheme/curve/header.go | 113 +++++++ core/scheme/curve/responder.go | 1 + core/scheme/gmsm/gmsm.go | 229 +++++++++++++ core/scheme/gmsm/header.go | 119 +++++++ core/scheme/gmsm/responder.go | 1 + core/tcpconn.go | 1 + {nhp => core}/transaction.go | 4 +- {nhp => core}/udpconn.go | 22 +- nhp/crypto.go | 413 ------------------------ nhp/packet.go | 371 --------------------- nhp/tcpconn.go | 1 - release/nhp-device/nhpdevice.def | 14 + server/config.go | 16 +- server/main/main.go | 8 +- server/msghandler.go | 40 +-- server/nhpauth.go | 12 +- server/plugins/example/main.go | 2 +- server/readme.md | 9 +- server/udpserver.go | 114 +++---- test/ecdh_test.go | 20 +- test/ecdsa_test.go | 15 +- test/packet_test.go | 36 ++- test/toml_test.go | 10 +- utils/crypto_test.go | 4 +- 55 files changed, 2485 insertions(+), 1388 deletions(-) rename ac/{udpdoor.go => udpac.go} (86%) rename {nhp => core}/benchmark/ecc_rsa_test.go (75%) rename {nhp => core}/benchmark/rsa_utils.go (100%) rename {nhp => core}/constants.go (99%) create mode 100644 core/crypto.go rename {nhp => core}/device.go (80%) create mode 100644 core/errors.go rename {nhp => core}/initiator.go (63%) rename {nhp => core}/kdf.go (99%) create mode 100644 core/main/main.go create mode 100644 core/main/nhpdevice.go create mode 100644 core/main/nhpdevicedef.h create mode 100644 core/packet.go rename {nhp => core}/peer.go (99%) rename {nhp => core}/readme.md (85%) rename {nhp => core}/responder.go (65%) create mode 100644 core/scheme/curve/curve.go create mode 100644 core/scheme/curve/header.go create mode 100644 core/scheme/curve/responder.go create mode 100644 core/scheme/gmsm/gmsm.go create mode 100644 core/scheme/gmsm/header.go create mode 100644 core/scheme/gmsm/responder.go create mode 100644 core/tcpconn.go rename {nhp => core}/transaction.go (98%) rename {nhp => core}/udpconn.go (87%) delete mode 100644 nhp/crypto.go delete mode 100644 nhp/packet.go delete mode 100644 nhp/tcpconn.go create mode 100644 release/nhp-device/nhpdevice.def diff --git a/Makefile b/Makefile index 6a3238ca..40e0ce01 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ generate-version-and-build: @$(MAKE) acd @$(MAKE) serverd @$(MAKE) agentsdk + @$(MAKE) devicesdk @$(MAKE) plugins @$(MAKE) archive @echo "$(COLOUR_GREEN)[OpenNHP] Build for platform ${OS_NAME} successfully done!$(END_COLOUR)" @@ -68,6 +69,12 @@ ifeq ($(OS_NAME), linux) gcc ./agent/sdkdemo/nhp-agent-demo.c -I ./release/nhp-agent -l:nhp-agent.so -L./release/nhp-agent -Wl,-rpath=. -o ./release/nhp-agent/nhp-agent-demo endif +devicesdk: +ifeq ($(OS_NAME), linux) + go build -a -trimpath -buildmode=c-shared -ldflags ${LD_FLAGS} -v -o ./release/nhp-device/nhpdevice.so ./core/main/main.go ./core/main/nhpdevice.go +# gcc ./core/sdkdemo/nhp-device-demo.c -I ./release/nhp-device -I ./core/main -l:nhpdevice.so -L./release/nhp-device -Wl,-rpath=. -o ./release/nhp-device/nhp-device-demo +endif + plugins: @if test -d $(NHP_PLUGINS); then $(MAKE) -C $(NHP_PLUGINS); fi @@ -76,4 +83,4 @@ archive: @cd release && mkdir -p archive && tar -czvf ./archive/$(PACKAGE_FILE) nhp-agent nhp-ac nhp-server @echo "$(COLOUR_GREEN)[opennhp] Package ${PACKAGE_FILE} archived!$(END_COLOUR)" -.PHONY: all generate-version-and-build init agentsdk plugins archive +.PHONY: all generate-version-and-build init agentsdk devicesdk plugins archive diff --git a/ac/config.go b/ac/config.go index ff098037..7402f11a 100644 --- a/ac/config.go +++ b/ac/config.go @@ -6,8 +6,8 @@ import ( "os" "path/filepath" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/utils" toml "github.com/pelletier/go-toml/v2" @@ -21,21 +21,21 @@ var ( ) type Config struct { - PrivateKeyBase64 string `json:"privateKey"` - ACId string `json:"acId"` - DefaultIp string `json:"defaultIp"` - AuthServiceId string `json:"aspId"` - ResourceIds []string `json:"resIds"` - Servers []*nhp.UdpPeer `json:"servers"` - IpPassMode int `json:"ipPassMode"` // 0: pass the knock source IP, 1: use pre-access mode and release the access source IP - LogLevel int `json:"logLevel"` + PrivateKeyBase64 string `json:"privateKey"` + ACId string `json:"acId"` + DefaultIp string `json:"defaultIp"` + AuthServiceId string `json:"aspId"` + ResourceIds []string `json:"resIds"` + Servers []*core.UdpPeer `json:"servers"` + IpPassMode int `json:"ipPassMode"` // 0: pass the knock source IP, 1: use pre-access mode and release the access source IP + LogLevel int `json:"logLevel"` } type Peers struct { - Servers []*nhp.UdpPeer + Servers []*core.UdpPeer } -func (d *UdpDoor) loadBaseConfig() error { +func (d *UdpAC) loadBaseConfig() error { // config.toml fileName := filepath.Join(ExeDirPath, "etc", "config.toml") if err := d.updateBaseConfig(fileName); err != nil { @@ -50,7 +50,7 @@ func (d *UdpDoor) loadBaseConfig() error { return nil } -func (d *UdpDoor) loadPeers() error { +func (d *UdpAC) loadPeers() error { // server.toml fileName := filepath.Join(ExeDirPath, "etc", "server.toml") if err := d.updateServerPeers(fileName); err != nil { @@ -66,7 +66,7 @@ func (d *UdpDoor) loadPeers() error { return nil } -func (d *UdpDoor) updateBaseConfig(file string) (err error) { +func (d *UdpAC) updateBaseConfig(file string) (err error) { utils.CatchPanicThenRun(func() { err = errLoadConfig }) @@ -107,7 +107,7 @@ func (d *UdpDoor) updateBaseConfig(file string) (err error) { return err } -func (d *UdpDoor) updateServerPeers(file string) (err error) { +func (d *UdpAC) updateServerPeers(file string) (err error) { utils.CatchPanicThenRun(func() { err = errLoadConfig }) @@ -119,12 +119,12 @@ func (d *UdpDoor) updateServerPeers(file string) (err error) { // update var peers Peers - serverPeerMap := make(map[string]*nhp.UdpPeer) + serverPeerMap := make(map[string]*core.UdpPeer) if err := toml.Unmarshal(content, &peers); err != nil { log.Error("failed to unmarshal server peer config: %v", err) } for _, p := range peers.Servers { - p.Type = nhp.NHP_SERVER + p.Type = core.NHP_SERVER d.device.AddPeer(p) serverPeerMap[p.PublicKeyBase64()] = p } @@ -142,11 +142,11 @@ func (d *UdpDoor) updateServerPeers(file string) (err error) { return err } -func (d *UdpDoor) IpPassMode() int { +func (d *UdpAC) IpPassMode() int { return d.config.IpPassMode } -func (d *UdpDoor) StopConfigWatch() { +func (d *UdpAC) StopConfigWatch() { if baseConfigWatch != nil { baseConfigWatch.Close() } diff --git a/ac/main/main.go b/ac/main/main.go index 0e874d87..c87cf600 100644 --- a/ac/main/main.go +++ b/ac/main/main.go @@ -8,7 +8,7 @@ import ( "syscall" "github.com/OpenNHP/opennhp/ac" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/version" "github.com/urfave/cli/v2" ) @@ -16,12 +16,12 @@ import ( func main() { app := cli.NewApp() app.Name = "nhp-ac" - app.Usage = "door entity for NHP protocol" + app.Usage = "ac entity for NHP protocol" app.Version = version.Version runCmd := &cli.Command{ Name: "run", - Usage: "create and run door process for NHP protocol", + Usage: "create and run ac process for NHP protocol", Action: func(c *cli.Context) error { return runApp() }, @@ -35,11 +35,11 @@ func main() { &cli.BoolFlag{Name: "sm2", Value: false, DisableDefaultText: true, Usage: "generate sm2 keys"}, }, Action: func(c *cli.Context) error { - var e nhp.Ecdh + var e core.Ecdh if c.Bool("sm2") { - e = nhp.NewECDH(nhp.ECC_SM2) + e = core.NewECDH(core.ECC_SM2) } else { - e = nhp.NewECDH(nhp.ECC_CURVE25519) + e = core.NewECDH(core.ECC_CURVE25519) } pub := e.PublicKeyBase64() priv := e.PrivateKeyBase64() @@ -66,7 +66,7 @@ func runApp() error { } exeDirPath := filepath.Dir(exeFilePath) - d := &ac.UdpDoor{} + d := &ac.UdpAC{} err = d.Start(exeDirPath, 4) if err != nil { return err diff --git a/ac/msghandler.go b/ac/msghandler.go index d81662bb..beb970aa 100644 --- a/ac/msghandler.go +++ b/ac/msghandler.go @@ -10,8 +10,8 @@ import ( "time" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/utils" ) @@ -21,20 +21,20 @@ const ( PASS_PRE_ACCESS_IP ) -func (d *UdpDoor) HandleACOperations(ppd *nhp.PacketParserData) (err error) { +func (d *UdpAC) HandleACOperations(ppd *core.PacketParserData) (err error) { defer d.wg.Done() d.wg.Add(1) acId := d.config.ACId dopMsg := &common.ServerACOpsMsg{} artMsg := &common.ACOpsResultMsg{} - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId // process ac operation func() { err = json.Unmarshal(ppd.BodyMessage, dopMsg) if err != nil { - log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, core.HeaderTypeToString(ppd.HeaderType), err) artMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() artMsg.ErrMsg = err.Error() return @@ -173,7 +173,7 @@ func (d *UdpDoor) HandleACOperations(ppd *nhp.PacketParserData) (err error) { case PASS_PRE_ACCESS_IP: fallthrough default: - // door open a temporary tcp or udp port for access + // ac open a temporary tcp or udp port for access dstIp := net.ParseIP(dstAddrs[0].Ip) if dstIp == nil { log.Error("ac(%s#%d)[HandleACOperations] destination IP %s is invalid", acId, transactionId, dstAddrs[0].Ip) @@ -326,8 +326,8 @@ func (d *UdpDoor) HandleACOperations(ppd *nhp.PacketParserData) (err error) { // send ac result artBytes, _ := json.Marshal(artMsg) - md := &nhp.MsgData{ - HeaderType: nhp.NHP_ART, + md := &core.MsgData{ + HeaderType: core.NHP_ART, TransactionId: transactionId, Compress: true, PrevParserData: ppd, @@ -347,7 +347,7 @@ func (d *UdpDoor) HandleACOperations(ppd *nhp.PacketParserData) (err error) { return nil } -func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPListener, au *AgentUser, timeoutSec int, dopMsg *common.ServerACOpsMsg) { +func (d *UdpAC) tcpTempAccessHandler(transactionId uint64, listener *net.TCPListener, au *AgentUser, timeoutSec int, dopMsg *common.ServerACOpsMsg) { defer d.wg.Done() defer d.DeleteAccessToken(au) defer listener.Close() @@ -376,8 +376,8 @@ func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPLi } remoteAddrStr := conn.RemoteAddr().String() - pkt := d.device.AllocateUdpPacket() - defer d.device.ReleaseUdpPacket(pkt) + pkt := d.device.AllocatePoolPacket() + defer d.device.ReleasePoolPacket(pkt) // monitor stop signals and quit connection earlier ctx, ctxCancel := context.WithDeadline(context.Background(), deadlineTime) @@ -385,26 +385,26 @@ func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPLi go d.tempConnTerminator(conn, ctx) // tcp recv common header first - n, err := conn.Read(pkt.Buf[:nhp.HeaderCommonSize]) - if err != nil || n < nhp.HeaderCommonSize { + n, err := conn.Read(pkt.Buf[:core.HeaderCommonSize]) + if err != nil || n < core.HeaderCommonSize { log.Error("ac(%s#%d)[HandleACOperations] failed to receive tcp packet header from remote address %s (%v)", acId, transactionId, remoteAddrStr, err) return } - pkt.Packet = pkt.Buf[:n] + pkt.Content = pkt.Buf[:n] // check type and payload size msgType, msgSize := pkt.HeaderTypeAndSize() - if msgType != nhp.NHP_ACC { - log.Error("ac(%s#%d)[HandleACOperations] message type is not %s, close connection", acId, transactionId, nhp.HeaderTypeToString(nhp.NHP_ACC)) + if msgType != core.NHP_ACC { + log.Error("ac(%s#%d)[HandleACOperations] message type is not %s, close connection", acId, transactionId, core.HeaderTypeToString(core.NHP_ACC)) return } var packetSize int flag := pkt.Flag() - if flag&nhp.NHP_FLAG_EXTENDEDLENGTH == 0 { - packetSize = nhp.HeaderSize + msgSize + if flag&core.NHP_FLAG_EXTENDEDLENGTH == 0 { + packetSize = core.HeaderSize + msgSize } else { - packetSize = nhp.HeaderSizeEx + msgSize + packetSize = core.HeaderSizeEx + msgSize } remainingSize := packetSize - n n, err = conn.Read(pkt.Buf[n:packetSize]) @@ -413,16 +413,15 @@ func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPLi return } - pkt.Packet = pkt.Buf[:packetSize] - log.Trace("receive tcp access packet (%s -> %s): %+v", remoteAddrStr, localAddrStr, pkt.Packet) + pkt.Content = pkt.Buf[:packetSize] + log.Trace("receive tcp access packet (%s -> %s): %+v", remoteAddrStr, localAddrStr, pkt.Content) log.Info("ac(%s#%d)[HandleACOperations] receive tcp access message (%s -> %s)", acId, transactionId, remoteAddrStr, localAddrStr) - pd := &nhp.PacketData{ + pd := &core.PacketData{ BasePacket: pkt, - ConnData: &nhp.ConnectionData{}, + ConnData: &core.ConnectionData{}, InitTime: time.Now().UnixNano(), - HeaderType: msgType, - DecryptedMsgCh: make(chan *nhp.PacketParserData), + DecryptedMsgCh: make(chan *core.PacketParserData), } if !d.IsRunning() { @@ -445,7 +444,7 @@ func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPLi accMsg := &common.AgentAccessMsg{} err = json.Unmarshal(accPpd.BodyMessage, accMsg) if err != nil { - log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, nhp.HeaderTypeToString(accPpd.HeaderType), err) + log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, core.HeaderTypeToString(accPpd.HeaderType), err) return } @@ -482,7 +481,7 @@ func (d *UdpDoor) tcpTempAccessHandler(transactionId uint64, listener *net.TCPLi } } -func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, au *AgentUser, timeoutSec int, dopMsg *common.ServerACOpsMsg) { +func (d *UdpAC) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, au *AgentUser, timeoutSec int, dopMsg *common.ServerACOpsMsg) { defer d.wg.Done() defer d.DeleteAccessToken(au) defer conn.Close() @@ -498,8 +497,8 @@ func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, return } - pkt := d.device.AllocateUdpPacket() - defer d.device.ReleaseUdpPacket(pkt) + pkt := d.device.AllocatePoolPacket() + defer d.device.ReleasePoolPacket(pkt) // monitor stop signals and quit connection earlier ctx, ctxCancel := context.WithDeadline(context.Background(), deadlineTime) @@ -508,27 +507,27 @@ func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, // udp recv, blocking until packet arrives or deadline reaches n, remoteAddr, err := conn.ReadFromUDP(pkt.Buf[:]) - if err != nil || n < nhp.HeaderCommonSize { + if err != nil || n < core.HeaderCommonSize { log.Error("ac(%s#%d)[HandleACOperations] failed to receive udp packet (%v)", acId, transactionId, err) return } remoteAddrStr := remoteAddr.String() - pkt.Packet = pkt.Buf[:n] + pkt.Content = pkt.Buf[:n] // check type and payload size msgType, msgSize := pkt.HeaderTypeAndSize() - if msgType != nhp.NHP_ACC { - log.Error("ac(%s#%d)[HandleACOperations] message type is not %s, close connection", acId, transactionId, nhp.HeaderTypeToString(nhp.NHP_ACC)) + if msgType != core.NHP_ACC { + log.Error("ac(%s#%d)[HandleACOperations] message type is not %s, close connection", acId, transactionId, core.HeaderTypeToString(core.NHP_ACC)) return } var packetSize int flag := pkt.Flag() - if flag&nhp.NHP_FLAG_EXTENDEDLENGTH == 0 { - packetSize = nhp.HeaderSize + msgSize + if flag&core.NHP_FLAG_EXTENDEDLENGTH == 0 { + packetSize = core.HeaderSize + msgSize } else { - packetSize = nhp.HeaderSizeEx + msgSize + packetSize = core.HeaderSizeEx + msgSize } if n != packetSize { @@ -536,15 +535,14 @@ func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, return } - log.Trace("receive udp access packet (%s -> %s): %+v", remoteAddrStr, localAddrStr, pkt.Packet) + log.Trace("receive udp access packet (%s -> %s): %+v", remoteAddrStr, localAddrStr, pkt.Content) log.Info("ac(%s#%d)[HandleACOperations] receive udp access message (%s -> %s)", acId, transactionId, remoteAddrStr, localAddrStr) - pd := &nhp.PacketData{ + pd := &core.PacketData{ BasePacket: pkt, - ConnData: &nhp.ConnectionData{}, + ConnData: &core.ConnectionData{}, InitTime: time.Now().UnixNano(), - HeaderType: msgType, - DecryptedMsgCh: make(chan *nhp.PacketParserData), + DecryptedMsgCh: make(chan *core.PacketParserData), } if !d.IsRunning() { @@ -567,7 +565,7 @@ func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, accMsg := &common.AgentAccessMsg{} err = json.Unmarshal(accPpd.BodyMessage, accMsg) if err != nil { - log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, nhp.HeaderTypeToString(accPpd.HeaderType), err) + log.Error("ac(%s#%d)[HandleACOperations] failed to parse %s message: %v", acId, transactionId, core.HeaderTypeToString(accPpd.HeaderType), err) return } @@ -611,7 +609,7 @@ func (d *UdpDoor) udpTempAccessHandler(transactionId uint64, conn *net.UDPConn, } } -func (d *UdpDoor) tempConnTerminator(conn net.Conn, ctx context.Context) { +func (d *UdpAC) tempConnTerminator(conn net.Conn, ctx context.Context) { select { case <-d.signals.stop: conn.Close() diff --git a/ac/readme.md b/ac/readme.md index ebb8b95a..3511eeb8 100644 --- a/ac/readme.md +++ b/ac/readme.md @@ -27,17 +27,17 @@ IP放行模式分为两种: `etc/config.toml` ```toml -[Door] - # (optional) assign an unique id for this door - DoorId = "abc_group_door_001" +[AC] + # (optional) assign an unique id for this ac + ACId = "abc_group_ac_001" # (mandatory) specify the private key in base64 format - DoorPrivateKey = "+B0RLGbe+nknJBZ0Fjt7kCBWfSTUttbUqkGteLfIp30=" + ACPrivateKey = "+B0RLGbe+nknJBZ0Fjt7kCBWfSTUttbUqkGteLfIp30=" # 0: default, passing the knock source IP # 1: use pre-access procedure to determine the passing source IP IpPassMode = 0 - # (optional) ID of authorization service provider this door belongs to + # (optional) ID of authorization service provider this ac belongs to AuthServiceId = "abc_group" - # (optional) ID of resources controlled by this door + # (optional) ID of resources controlled by this ac ResourceIds = ["abc_group_web_server", "abc_group_api_server"] # (optional) ID of organization OrganizationId = "5f3e36149fa95c0414408ad4" diff --git a/ac/udpdoor.go b/ac/udpac.go similarity index 86% rename from ac/udpdoor.go rename to ac/udpac.go index c1069c44..5ce5097c 100644 --- a/ac/udpdoor.go +++ b/ac/udpac.go @@ -13,8 +13,8 @@ import ( "time" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/utils" "github.com/OpenNHP/opennhp/version" ) @@ -31,7 +31,7 @@ type AgentUser struct { } func (au *AgentUser) Hash() string { - au.hash = nhp.NewHash(nhp.HASH_SM3) + au.hash = core.NewHash(core.HASH_SM3) au.hash.Write([]byte(au.UserId)) au.hash.Write([]byte(au.DeviceId)) au.hash.Write([]byte(au.OrganizationId)) @@ -42,7 +42,7 @@ func (au *AgentUser) Hash() string { type AgentUserCodeMap = map[string]*map[string]string // agent hash string first letter > agent hash string > token -type UdpDoor struct { +type UdpAC struct { config *Config iptables *utils.IPTables ipset *utils.IPSet @@ -58,12 +58,12 @@ type UdpDoor struct { remoteConnectionMap map[string]*UdpConn // indexed by remote UDP address serverPeerMutex sync.Mutex - serverPeerMap map[string]*nhp.UdpPeer // indexed by server's public key + serverPeerMap map[string]*core.UdpPeer // indexed by server's public key AgentUserTokenMutex sync.Mutex agentUserCodeMap AgentUserCodeMap - device *nhp.Device + device *core.Device wg sync.WaitGroup running atomic.Bool @@ -72,12 +72,12 @@ type UdpDoor struct { serverMapUpdated chan struct{} } - recvMsgCh <-chan *nhp.PacketParserData - sendMsgCh chan *nhp.MsgData + recvMsgCh <-chan *core.PacketParserData + sendMsgCh chan *core.MsgData } type UdpConn struct { - ConnData *nhp.ConnectionData + ConnData *core.ConnectionData netConn *net.UDPConn connected atomic.Bool externalAddr string @@ -92,7 +92,7 @@ func (c *UdpConn) Close() { dirPath: the path of app or shared library entry point logLevel: 0: silent, 1: error, 2: info, 3: debug, 4: verbose */ -func (d *UdpDoor) Start(dirPath string, logLevel int) (err error) { +func (d *UdpAC) Start(dirPath string, logLevel int) (err error) { common.ExeDirPath = dirPath ExeDirPath = dirPath // init logger @@ -129,14 +129,14 @@ func (d *UdpDoor) Start(dirPath string, logLevel int) (err error) { return fmt.Errorf("private key parse error %v", err) } - d.device = nhp.NewDevice(nhp.NHP_AC, prk, nil) + d.device = core.NewDevice(core.NHP_AC, prk, nil) if d.device == nil { log.Critical("failed to create device %v\n", err) return fmt.Errorf("failed to create device %v", err) } d.remoteConnectionMap = make(map[string]*UdpConn) - d.serverPeerMap = make(map[string]*nhp.UdpPeer) + d.serverPeerMap = make(map[string]*core.UdpPeer) d.agentUserCodeMap = make(AgentUserCodeMap) // load peers @@ -146,12 +146,12 @@ func (d *UdpDoor) Start(dirPath string, logLevel int) (err error) { d.signals.serverMapUpdated = make(chan struct{}, 1) d.recvMsgCh = d.device.DecryptedMsgQueue - d.sendMsgCh = make(chan *nhp.MsgData, nhp.SendQueueSize) + d.sendMsgCh = make(chan *core.MsgData, core.SendQueueSize) // start device routines d.device.Start() - // start door routines + // start ac routines d.wg.Add(3) go d.sendMessageRoutine() go d.recvMessageRoutine() @@ -161,7 +161,7 @@ func (d *UdpDoor) Start(dirPath string, logLevel int) (err error) { return nil } -func (d *UdpDoor) Stop() { +func (d *UdpAC) Stop() { d.running.Store(false) close(d.signals.stop) @@ -177,11 +177,11 @@ func (d *UdpDoor) Stop() { d.log.Close() } -func (d *UdpDoor) IsRunning() bool { +func (d *UdpAC) IsRunning() bool { return d.running.Load() } -func (d *UdpDoor) newConnection(addr *net.UDPAddr) (conn *UdpConn) { +func (d *UdpAC) newConnection(addr *net.UDPAddr) (conn *UdpConn) { conn = &UdpConn{} var err error // unlike tcp, udp dial is fast (just socket bind), so no need to run in a thread @@ -201,15 +201,15 @@ func (d *UdpDoor) newConnection(addr *net.UDPAddr) (conn *UdpConn) { log.Info("Dial up new UDP connection from %s to %s", localAddr.String(), addr.String()) - conn.ConnData = &nhp.ConnectionData{ + conn.ConnData = &core.ConnectionData{ Device: d.device, - CookieStore: &nhp.CookieStore{}, - RemoteTransactionMap: make(map[uint64]*nhp.RemoteTransaction), + CookieStore: &core.CookieStore{}, + RemoteTransactionMap: make(map[uint64]*core.RemoteTransaction), LocalAddr: localAddr, RemoteAddr: addr, TimeoutMs: DefaultConnectionTimeoutMs, - SendQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), - RecvQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), + SendQueue: make(chan *core.Packet, PacketQueueSizePerConnection), + RecvQueue: make(chan *core.Packet, PacketQueueSizePerConnection), BlockSignal: make(chan struct{}), SetTimeoutSignal: make(chan struct{}), StopSignal: make(chan struct{}), @@ -222,7 +222,7 @@ func (d *UdpDoor) newConnection(addr *net.UDPAddr) (conn *UdpConn) { return conn } -func (d *UdpDoor) sendMessageRoutine() { +func (d *UdpAC) sendMessageRoutine() { defer d.wg.Done() defer log.Info("sendMessageRoutine stopped") @@ -273,24 +273,24 @@ func (d *UdpDoor) sendMessageRoutine() { } } -func (d *UdpDoor) SendPacket(pkt *nhp.UdpPacket, conn *UdpConn) (n int, err error) { +func (d *UdpAC) SendPacket(pkt *core.Packet, conn *UdpConn) (n int, err error) { defer func() { atomic.AddUint64(&d.stats.totalSendBytes, uint64(n)) atomic.StoreInt64(&conn.ConnData.LastLocalSendTime, time.Now().UnixNano()) if !pkt.KeepAfterSend { - d.device.ReleaseUdpPacket(pkt) + d.device.ReleasePoolPacket(pkt) } }() - pktType := nhp.HeaderTypeToString(pkt.HeaderType) - //log.Debug("Send [%s] packet (%s -> %s): %+v", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Packet) - log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - log.Evaluate("Send [%s] packet (%s -> %s, %d bytes)", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - return conn.netConn.Write(pkt.Packet) + pktType := core.HeaderTypeToString(pkt.HeaderType) + //log.Debug("Send [%s] packet (%s -> %s): %+v", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Content) + log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + log.Evaluate("Send [%s] packet (%s -> %s, %d bytes)", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + return conn.netConn.Write(pkt.Content) } -func (d *UdpDoor) recvPacketRoutine(conn *UdpConn) { +func (d *UdpAC) recvPacketRoutine(conn *UdpConn) { addrStr := conn.ConnData.RemoteAddr.String() defer conn.ConnData.Done() @@ -307,10 +307,10 @@ func (d *UdpDoor) recvPacketRoutine(conn *UdpConn) { } // udp recv, blocking until packet arrives or netConn.Close() - pkt := d.device.AllocateUdpPacket() + pkt := d.device.AllocatePoolPacket() n, err := conn.netConn.Read(pkt.Buf[:]) if err != nil { - d.device.ReleaseUdpPacket(pkt) + d.device.ReleasePoolPacket(pkt) if n == 0 { // udp connection closed, it is not an error return @@ -323,21 +323,21 @@ func (d *UdpDoor) recvPacketRoutine(conn *UdpConn) { atomic.AddUint64(&d.stats.totalRecvBytes, uint64(n)) // check minimal length - if n < nhp.HeaderSize { - d.device.ReleaseUdpPacket(pkt) + if n < core.HeaderSize { + d.device.ReleasePoolPacket(pkt) log.Error("Received UDP packet from %s is too short, discard", addrStr) continue } - pkt.Packet = pkt.Buf[:n] - //log.Trace("receive udp packet (%s -> %s): %+v", conn.ConnData.RemoteAddr.String(), conn.ConnData.LocalAddr.String(), pkt.Packet) + pkt.Content = pkt.Buf[:n] + //log.Trace("receive udp packet (%s -> %s): %+v", conn.ConnData.RemoteAddr.String(), conn.ConnData.LocalAddr.String(), pkt.Content) typ, _, err := d.device.RecvPrecheck(pkt) - msgType := nhp.HeaderTypeToString(typ) + msgType := core.HeaderTypeToString(typ) log.Info("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, conn.ConnData.LocalAddr.String(), n) log.Evaluate("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, conn.ConnData.LocalAddr.String(), n) if err != nil { - d.device.ReleaseUdpPacket(pkt) + d.device.ReleasePoolPacket(pkt) log.Warning("Receive [%s] packet (%s -> %s), precheck error: %v", msgType, addrStr, conn.ConnData.LocalAddr.String(), err) log.Evaluate("Receive [%s] packet (%s -> %s) precheck error: %v", msgType, addrStr, conn.ConnData.LocalAddr.String(), err) continue @@ -349,7 +349,7 @@ func (d *UdpDoor) recvPacketRoutine(conn *UdpConn) { } } -func (d *UdpDoor) connectionRoutine(conn *UdpConn) { +func (d *UdpAC) connectionRoutine(conn *UdpConn) { addrStr := conn.ConnData.RemoteAddr.String() defer d.wg.Done() @@ -398,10 +398,10 @@ func (d *UdpDoor) connectionRoutine(conn *UdpConn) { if pkt == nil { continue } - log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Packet), addrStr) + log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Content), addrStr) - if pkt.HeaderType == nhp.NHP_KPL { - d.device.ReleaseUdpPacket(pkt) + if pkt.HeaderType == core.NHP_KPL { + d.device.ReleasePoolPacket(pkt) log.Info("Receive [NHP_KPL] message (%s -> %s)", addrStr, conn.ConnData.LocalAddr.String()) continue } @@ -416,7 +416,7 @@ func (d *UdpDoor) connectionRoutine(conn *UdpConn) { } } - pd := &nhp.PacketData{ + pd := &core.PacketData{ BasePacket: pkt, ConnData: conn.ConnData, InitTime: atomic.LoadInt64(&conn.ConnData.LastLocalRecvTime), @@ -431,7 +431,7 @@ func (d *UdpDoor) connectionRoutine(conn *UdpConn) { } } -func (d *UdpDoor) recvMessageRoutine() { +func (d *UdpAC) recvMessageRoutine() { defer d.wg.Done() defer log.Info("recvMessageRoutine stopped") @@ -451,7 +451,7 @@ func (d *UdpDoor) recvMessageRoutine() { } switch ppd.HeaderType { - case nhp.NHP_AOP: + case core.NHP_AOP: // deal with NHP_AOP message go d.HandleACOperations(ppd) } @@ -460,7 +460,7 @@ func (d *UdpDoor) recvMessageRoutine() { } // keep interaction between ac and server in certain time interval to keep outwards ip path active -func (d *UdpDoor) maintainServerConnectionRoutine() { +func (d *UdpAC) maintainServerConnectionRoutine() { defer d.wg.Done() defer log.Info("maintainServerConnectionRoutine stopped") @@ -536,7 +536,7 @@ func (d *UdpDoor) maintainServerConnectionRoutine() { } } -func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync.WaitGroup, serverFailCount *int32, quit <-chan struct{}) { +func (d *UdpAC) serverDiscovery(server *core.UdpPeer, discoveryRoutineWg *sync.WaitGroup, serverFailCount *int32, quit <-chan struct{}) { defer discoveryRoutineWg.Done() acId := d.config.ACId @@ -590,14 +590,14 @@ func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync. } aolBytes, _ := json.Marshal(aolMsg) - aolMd := &nhp.MsgData{ + aolMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_AOL, + HeaderType: core.NHP_AOL, TransactionId: d.device.NextCounterIndex(), Compress: true, PeerPk: peerPbk, Message: aolBytes, - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } if !d.IsRunning() { @@ -644,8 +644,8 @@ func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync. return } - if ppd.HeaderType != nhp.NHP_AAK { - log.Error("ac(%s#%d)[ACOnline] response from server %s has wrong type: %s", acId, aolMd.TransactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType)) + if ppd.HeaderType != core.NHP_AAK { + log.Error("ac(%s#%d)[ACOnline] response from server %s has wrong type: %s", acId, aolMd.TransactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType return } @@ -653,7 +653,7 @@ func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync. aakMsg := &common.ServerACAckMsg{} err = json.Unmarshal(ppd.BodyMessage, aakMsg) if err != nil { - log.Error("ac(%s#%d)[HandleACAck] failed to parse %s message: %v", acId, ppd.SenderId, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("ac(%s#%d)[HandleACAck] failed to parse %s message: %v", acId, ppd.SenderTrxId, core.HeaderTypeToString(ppd.HeaderType), err) return } @@ -671,9 +671,9 @@ func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync. } else if connected { if (currTime - lastSendTime) > int64(ServerKeepaliveInterval*time.Second) { // send NHP_KPL to server if no send happens within ServerKeepaliveInterval - md := &nhp.MsgData{ + md := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_KPL, + HeaderType: core.NHP_KPL, //PeerPk: peerPbk, // pubkey not needed TransactionId: d.device.NextCounterIndex(), } @@ -694,8 +694,8 @@ func (d *UdpDoor) serverDiscovery(server *nhp.UdpPeer, discoveryRoutineWg *sync. } } -func (d *UdpDoor) AddServerPeer(server *nhp.UdpPeer) { - if server.DeviceType() == nhp.NHP_SERVER { +func (d *UdpAC) AddServerPeer(server *core.UdpPeer) { + if server.DeviceType() == core.NHP_SERVER { d.device.AddPeer(server) d.serverPeerMutex.Lock() @@ -709,7 +709,7 @@ func (d *UdpDoor) AddServerPeer(server *nhp.UdpPeer) { } } -func (d *UdpDoor) RemoveServerPeer(serverKey string) { +func (d *UdpAC) RemoveServerPeer(serverKey string) { d.serverPeerMutex.Lock() beforeSize := len(d.serverPeerMap) delete(d.serverPeerMap, serverKey) @@ -724,7 +724,7 @@ func (d *UdpDoor) RemoveServerPeer(serverKey string) { } } -func (d *UdpDoor) GenerateAccessToken(au *AgentUser) string { +func (d *UdpAC) GenerateAccessToken(au *AgentUser) string { hashStr := au.Hash() timeStr := strconv.FormatInt(time.Now().UnixNano(), 10) au.hash.Write([]byte(timeStr)) @@ -747,7 +747,7 @@ func (d *UdpDoor) GenerateAccessToken(au *AgentUser) string { return token } -func (d *UdpDoor) VerifyAccessToken(au *AgentUser, token string) bool { +func (d *UdpAC) VerifyAccessToken(au *AgentUser, token string) bool { hashStr := au.Hash() d.AgentUserTokenMutex.Lock() @@ -769,7 +769,7 @@ func (d *UdpDoor) VerifyAccessToken(au *AgentUser, token string) bool { return false } -func (d *UdpDoor) DeleteAccessToken(au *AgentUser) { +func (d *UdpAC) DeleteAccessToken(au *AgentUser) { hashStr := au.Hash() d.AgentUserTokenMutex.Lock() @@ -785,7 +785,7 @@ func (d *UdpDoor) DeleteAccessToken(au *AgentUser) { } // if the server uses hostname as destination, find the correct peer with the actual IP address -func (d *UdpDoor) ResolvePeer(peer *nhp.UdpPeer) (*nhp.UdpPeer, net.Addr) { +func (d *UdpAC) ResolvePeer(peer *core.UdpPeer) (*core.UdpPeer, net.Addr) { addr := peer.SendAddr() if addr == nil { return peer, nil diff --git a/agent/config.go b/agent/config.go index 179a5a4f..ddd6d6a2 100644 --- a/agent/config.go +++ b/agent/config.go @@ -6,8 +6,8 @@ import ( "os" "path/filepath" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/utils" toml "github.com/pelletier/go-toml/v2" @@ -28,7 +28,7 @@ type Config struct { } type Peers struct { - Servers []*nhp.UdpPeer + Servers []*core.UdpPeer } type Resources struct { @@ -133,12 +133,12 @@ func (a *UdpAgent) updateServerPeers(file string) (err error) { // update var peers Peers - serverPeerMap := make(map[string]*nhp.UdpPeer) + serverPeerMap := make(map[string]*core.UdpPeer) if err := toml.Unmarshal(content, &peers); err != nil { log.Error("failed to unmarshal server config: %v", err) } for _, p := range peers.Servers { - p.Type = nhp.NHP_SERVER + p.Type = core.NHP_SERVER a.device.AddPeer(p) serverPeerMap[p.PublicKeyBase64()] = p } diff --git a/agent/knock.go b/agent/knock.go index 3cacbb7b..e6e0bb3c 100644 --- a/agent/knock.go +++ b/agent/knock.go @@ -8,15 +8,15 @@ import ( "time" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" ) func (a *UdpAgent) Knock(res *KnockTarget) (ackMsg *common.ServerKnockAckMsg, err error) { defer a.wg.Done() a.wg.Add(1) - errWaitTime := (nhp.AgentLocalTransactionResponseTimeoutMs - 100) * time.Millisecond + errWaitTime := (core.AgentLocalTransactionResponseTimeoutMs - 100) * time.Millisecond startTime := time.Now() ackMsg, err = a.knockRequest(res, false) @@ -39,7 +39,7 @@ func (a *UdpAgent) Knock(res *KnockTarget) (ackMsg *common.ServerKnockAckMsg, er return ackMsg, err } - // deal with door PASS_ACCESS_IP mode + // deal with ac PASS_ACCESS_IP mode if len(ackMsg.PreAccessActions) > 0 { a.preAccessRequest(ackMsg) } @@ -76,17 +76,17 @@ func (a *UdpAgent) knockRequest(res *KnockTarget, useCookie bool) (ackMsg *commo a.knockUserMutex.RUnlock() knkBytes, _ := json.Marshal(knkMsg) - knkMd := &nhp.MsgData{ + knkMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_KNK, + HeaderType: core.NHP_KNK, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: knkBytes, PeerPk: server.PublicKey(), - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } if useCookie { - knkMd.HeaderType = nhp.NHP_RKN + knkMd.HeaderType = core.NHP_RKN } ackMsg = &common.ServerKnockAckMsg{} @@ -113,7 +113,7 @@ func (a *UdpAgent) knockRequest(res *KnockTarget, useCookie bool) (ackMsg *commo return ackMsg, err } - if serverPpd.HeaderType == nhp.NHP_COK { + if serverPpd.HeaderType == core.NHP_COK { log.Error("agent(%s#%d)[KnockRequest] terminated by server's cookie message", knkMsg.UserId, knkMd.TransactionId) err = common.ErrKnockTerminatedByCookie ackMsg.ErrCode = common.ErrKnockTerminatedByCookie.ErrorCode() @@ -121,8 +121,8 @@ func (a *UdpAgent) knockRequest(res *KnockTarget, useCookie bool) (ackMsg *commo return ackMsg, err } - if serverPpd.HeaderType != nhp.NHP_ACK { - log.Error("agent(%s#%d)[KnockRequest] response has wrong type: %s", knkMsg.UserId, knkMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType)) + if serverPpd.HeaderType != core.NHP_ACK { + log.Error("agent(%s#%d)[KnockRequest] response has wrong type: %s", knkMsg.UserId, knkMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType ackMsg.ErrCode = common.ErrTransactionRepliedWithWrongType.ErrorCode() ackMsg.ErrMsg = err.Error() @@ -131,7 +131,7 @@ func (a *UdpAgent) knockRequest(res *KnockTarget, useCookie bool) (ackMsg *commo err = json.Unmarshal(serverPpd.BodyMessage, ackMsg) if err != nil { - log.Error("agent(%s#%d)[KnockRequest] failed to parse %s message: %v", knkMsg.UserId, knkMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType), err) + log.Error("agent(%s#%d)[KnockRequest] failed to parse %s message: %v", knkMsg.UserId, knkMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType), err) ackMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() ackMsg.ErrMsg = err.Error() return ackMsg, err @@ -174,14 +174,14 @@ func (a *UdpAgent) ExitKnockRequest(res *KnockTarget) (ackMsg *common.ServerKnoc a.knockUserMutex.RUnlock() knkBytes, _ := json.Marshal(knkMsg) - knkMd := &nhp.MsgData{ + knkMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_EXT, + HeaderType: core.NHP_EXT, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: knkBytes, PeerPk: server.PublicKey(), - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } ackMsg = &common.ServerKnockAckMsg{} @@ -208,7 +208,7 @@ func (a *UdpAgent) ExitKnockRequest(res *KnockTarget) (ackMsg *common.ServerKnoc return ackMsg, err } - if serverPpd.HeaderType == nhp.NHP_COK { + if serverPpd.HeaderType == core.NHP_COK { log.Error("agent(%s#%d)[ExitKnockRequest] terminated by server's cookie message", knkMsg.UserId, knkMd.TransactionId) err = common.ErrKnockTerminatedByCookie ackMsg.ErrCode = common.ErrKnockTerminatedByCookie.ErrorCode() @@ -216,8 +216,8 @@ func (a *UdpAgent) ExitKnockRequest(res *KnockTarget) (ackMsg *common.ServerKnoc return ackMsg, err } - if serverPpd.HeaderType != nhp.NHP_ACK { - log.Error("agent(%s#%d)[ExitKnockRequest] response has wrong type: %s", knkMsg.UserId, knkMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType)) + if serverPpd.HeaderType != core.NHP_ACK { + log.Error("agent(%s#%d)[ExitKnockRequest] response has wrong type: %s", knkMsg.UserId, knkMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType ackMsg.ErrCode = common.ErrTransactionRepliedWithWrongType.ErrorCode() ackMsg.ErrMsg = err.Error() @@ -226,7 +226,7 @@ func (a *UdpAgent) ExitKnockRequest(res *KnockTarget) (ackMsg *common.ServerKnoc err = json.Unmarshal(serverPpd.BodyMessage, ackMsg) if err != nil { - log.Error("agent(%s#%d)[ExitKnockRequest] failed to parse %s message: %v", knkMsg.UserId, knkMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType), err) + log.Error("agent(%s#%d)[ExitKnockRequest] failed to parse %s message: %v", knkMsg.UserId, knkMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType), err) ackMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() ackMsg.ErrMsg = err.Error() return ackMsg, err @@ -284,7 +284,7 @@ func (a *UdpAgent) processPreAccessAction(info *common.PreAccessInfo) error { IP: acIp, Port: acPort, } - acPeer := &nhp.UdpPeer{ + acPeer := &core.UdpPeer{ PubKeyBase64: info.ACPubKey, Ip: info.AccessIp, Port: acPort, @@ -303,14 +303,14 @@ func (a *UdpAgent) processPreAccessAction(info *common.PreAccessInfo) error { a.knockUserMutex.RUnlock() accBytes, _ := json.Marshal(accMsg) - accMd := &nhp.MsgData{ + accMd := &core.MsgData{ RemoteAddr: udpACAddr, - HeaderType: nhp.NHP_ACC, + HeaderType: core.NHP_ACC, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: accBytes, PeerPk: acPk, - EncryptedPktCh: make(chan *nhp.MsgAssemblerData), + EncryptedPktCh: make(chan *core.MsgAssemblerData), } if !a.IsRunning() { @@ -331,11 +331,11 @@ func (a *UdpAgent) processPreAccessAction(info *common.PreAccessInfo) error { } // copy the packet for GC recycling and release the original packet buffer - packetBytes := make([]byte, len(accMad.BasePacket.Packet)) - copy(packetBytes, accMad.BasePacket.Packet) + packetBytes := make([]byte, len(accMad.BasePacket.Content)) + copy(packetBytes, accMad.BasePacket.Content) accMad.Destroy() - // open new routine(s) to send access packet to door's temporary port + // open new routine(s) to send access packet to ac's temporary port go func(packet []byte, tcpAddr *net.TCPAddr) { // dial tcp connection and send accMad packet conn, err := net.DialTCP("tcp", nil, tcpAddr) diff --git a/agent/main/export.go b/agent/main/export.go index 4824f48e..4cc6dc06 100644 --- a/agent/main/export.go +++ b/agent/main/export.go @@ -14,7 +14,7 @@ import ( "github.com/OpenNHP/opennhp/agent" "github.com/OpenNHP/opennhp/common" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" ) var gAgentInstance *agent.UdpAgent @@ -149,8 +149,8 @@ func nhp_agent_add_server(pubkey *C.char, ip *C.char, host *C.char, port C.int, serverPort = 62206 // use default server listening port } - serverPeer := &nhp.UdpPeer{ - Type: nhp.NHP_SERVER, + serverPeer := &core.UdpPeer{ + Type: core.NHP_SERVER, PubKeyBase64: deepCopyCString(pubkey), Ip: deepCopyCString(ip), Port: serverPort, @@ -345,14 +345,14 @@ func nhp_agent_exit_resource(aspId *C.char, resId *C.char, serverAddr *C.char) b // //export nhp_generate_keys func nhp_generate_keys(cipherType C.int) *C.char { - var e nhp.Ecdh - switch nhp.EccTypeEnum(cipherType) { - case nhp.ECC_SM2: - e = nhp.NewECDH(nhp.ECC_SM2) - case nhp.ECC_CURVE25519: + var e core.Ecdh + switch core.EccTypeEnum(cipherType) { + case core.ECC_SM2: + e = core.NewECDH(core.ECC_SM2) + case core.ECC_CURVE25519: fallthrough default: - e = nhp.NewECDH(nhp.ECC_CURVE25519) + e = core.NewECDH(core.ECC_CURVE25519) } pub := e.PublicKeyBase64() priv := e.PrivateKeyBase64() @@ -376,7 +376,7 @@ func nhp_privkey_to_pubkey(cipherType C.int, privateBase64 *C.char) *C.char { return nil } - e := nhp.ECDHFromKey(nhp.EccTypeEnum(cipherType), privKeyBytes) + e := core.ECDHFromKey(core.EccTypeEnum(cipherType), privKeyBytes) if e == nil { return nil } diff --git a/agent/main/main.go b/agent/main/main.go index 89a92914..52223fff 100644 --- a/agent/main/main.go +++ b/agent/main/main.go @@ -9,7 +9,7 @@ import ( "syscall" "github.com/OpenNHP/opennhp/agent" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/version" "github.com/urfave/cli/v2" ) @@ -36,11 +36,11 @@ func main() { &cli.BoolFlag{Name: "sm2", Value: false, DisableDefaultText: true, Usage: "generate sm2 keys"}, }, Action: func(c *cli.Context) error { - var e nhp.Ecdh + var e core.Ecdh if c.Bool("sm2") { - e = nhp.NewECDH(nhp.ECC_SM2) + e = core.NewECDH(core.ECC_SM2) } else { - e = nhp.NewECDH(nhp.ECC_CURVE25519) + e = core.NewECDH(core.ECC_CURVE25519) } pub := e.PublicKeyBase64() priv := e.PrivateKeyBase64() @@ -62,11 +62,11 @@ func main() { if err != nil { return err } - cipherType := nhp.ECC_CURVE25519 + cipherType := core.ECC_CURVE25519 if c.Bool("sm2") { - cipherType = nhp.ECC_SM2 + cipherType = core.ECC_SM2 } - e := nhp.ECDHFromKey(cipherType, privKey) + e := core.ECDHFromKey(cipherType, privKey) if e == nil { return fmt.Errorf("invalid input key") } diff --git a/agent/msghandler.go b/agent/msghandler.go index dc60fa3f..921b4cfc 100644 --- a/agent/msghandler.go +++ b/agent/msghandler.go @@ -5,11 +5,11 @@ import ( "encoding/json" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" ) -func (a *UdpAgent) HandleCookieMessage(ppd *nhp.PacketParserData) bool { +func (a *UdpAgent) HandleCookieMessage(ppd *core.PacketParserData) bool { defer a.wg.Done() a.wg.Add(1) @@ -18,13 +18,13 @@ func (a *UdpAgent) HandleCookieMessage(ppd *nhp.PacketParserData) bool { err := json.Unmarshal(ppd.BodyMessage, cokMsg) if err != nil { - log.Error("agent[HandleCookieMessage] failed to parse %s message: %v", nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("agent[HandleCookieMessage] failed to parse %s message: %v", core.HeaderTypeToString(ppd.HeaderType), err) return false } // update cookie cokBytes, _ := base64.StdEncoding.DecodeString(cokMsg.Cookie) - copy(ppd.ConnData.CookieStore.Cookie[:], cokBytes) + copy(ppd.ConnData.CookieStore.CurrCookie[:], cokBytes) transactionId := cokMsg.TransactionId // note this transaction id is in message structure, not the one in packet transaction := a.device.FindLocalTransaction(transactionId) diff --git a/agent/request.go b/agent/request.go index 4ebd37b6..8bdbbf4d 100644 --- a/agent/request.go +++ b/agent/request.go @@ -5,8 +5,8 @@ import ( "net" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" ) // note: code in request.go is for nhp-agent to send request to nhp-server. @@ -35,9 +35,9 @@ func (a *UdpAgent) RequestOtp(target *KnockTarget) error { return common.ErrKnockServerNotFound } - otpMd := &nhp.MsgData{ + otpMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_OTP, + HeaderType: core.NHP_OTP, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: otpBytes, @@ -82,14 +82,14 @@ func (a *UdpAgent) RegisterPublicKey(otp string, target *KnockTarget) (rakMsg *c } addrStr := sendAddr.String() - regMd := &nhp.MsgData{ + regMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_REG, + HeaderType: core.NHP_REG, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: regBytes, PeerPk: server.PublicKey(), - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } if !a.IsRunning() { @@ -110,8 +110,8 @@ func (a *UdpAgent) RegisterPublicKey(otp string, target *KnockTarget) (rakMsg *c return nil, err } - if serverPpd.HeaderType != nhp.NHP_RAK { - log.Error("agent(%s#%d)[RegisterPublicKey] response has wrong type: %s", regMsg.UserId, regMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType)) + if serverPpd.HeaderType != core.NHP_RAK { + log.Error("agent(%s#%d)[RegisterPublicKey] response has wrong type: %s", regMsg.UserId, regMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType return nil, err } @@ -119,7 +119,7 @@ func (a *UdpAgent) RegisterPublicKey(otp string, target *KnockTarget) (rakMsg *c rakMsg = &common.ServerRegisterAckMsg{} err = json.Unmarshal(serverPpd.BodyMessage, rakMsg) if err != nil { - log.Error("agent(%s#%d)[RegisterPublicKey] failed to parse %s message: %v", regMsg.UserId, regMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType), err) + log.Error("agent(%s#%d)[RegisterPublicKey] failed to parse %s message: %v", regMsg.UserId, regMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType), err) return nil, err } @@ -158,14 +158,14 @@ func (a *UdpAgent) ListResource(target *KnockTarget) (lrtMsg *common.ServerListR } addrStr := sendAddr.String() - lstMd := &nhp.MsgData{ + lstMd := &core.MsgData{ RemoteAddr: sendAddr.(*net.UDPAddr), - HeaderType: nhp.NHP_LST, + HeaderType: core.NHP_LST, TransactionId: a.device.NextCounterIndex(), Compress: true, Message: lstBytes, PeerPk: server.PublicKey(), - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } if !a.IsRunning() { @@ -186,8 +186,8 @@ func (a *UdpAgent) ListResource(target *KnockTarget) (lrtMsg *common.ServerListR return nil, err } - if serverPpd.HeaderType != nhp.NHP_LRT { - log.Error("agent(%s#%d)[ListResource] response has wrong type: %s", lstMsg.UserId, lstMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType)) + if serverPpd.HeaderType != core.NHP_LRT { + log.Error("agent(%s#%d)[ListResource] response has wrong type: %s", lstMsg.UserId, lstMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType return nil, err } @@ -195,7 +195,7 @@ func (a *UdpAgent) ListResource(target *KnockTarget) (lrtMsg *common.ServerListR lrtMsg = &common.ServerListResultMsg{} err = json.Unmarshal(serverPpd.BodyMessage, lrtMsg) if err != nil { - log.Error("agent(%s#%d)[ListResource] failed to parse %s message: %v", lstMsg.UserId, lstMd.TransactionId, nhp.HeaderTypeToString(serverPpd.HeaderType), err) + log.Error("agent(%s#%d)[ListResource] failed to parse %s message: %v", lstMsg.UserId, lstMd.TransactionId, core.HeaderTypeToString(serverPpd.HeaderType), err) return nil, err } diff --git a/agent/udpagent.go b/agent/udpagent.go index f01f9d5c..690abb27 100644 --- a/agent/udpagent.go +++ b/agent/udpagent.go @@ -10,8 +10,8 @@ import ( "time" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/version" ) @@ -38,7 +38,7 @@ func (res *KnockResource) Id() string { type KnockTarget struct { sync.Mutex KnockResource - ServerPeer *nhp.UdpPeer + ServerPeer *core.UdpPeer LastKnockSuccessTime time.Time } @@ -49,14 +49,14 @@ func (kt *KnockTarget) SetResource(res *KnockResource) { kt.KnockResource = *res } -func (kt *KnockTarget) SetServer(peer *nhp.UdpPeer) { +func (kt *KnockTarget) SetServer(peer *core.UdpPeer) { kt.Lock() defer kt.Unlock() kt.ServerPeer = peer } -func (kt *KnockTarget) Server() *nhp.UdpPeer { +func (kt *KnockTarget) Server() *core.UdpPeer { kt.Lock() defer kt.Unlock() @@ -79,9 +79,9 @@ type UdpAgent struct { knockTargetMap map[string]*KnockTarget // indexed by aspId + resId serverPeerMutex sync.Mutex - serverPeerMap map[string]*nhp.UdpPeer // indexed by server's public key + serverPeerMap map[string]*core.UdpPeer // indexed by server's public key - device *nhp.Device + device *core.Device wg sync.WaitGroup running atomic.Bool @@ -91,8 +91,8 @@ type UdpAgent struct { knockTargetMapUpdated chan struct{} } - recvMsgCh <-chan *nhp.PacketParserData - sendMsgCh chan *nhp.MsgData + recvMsgCh <-chan *core.PacketParserData + sendMsgCh chan *core.MsgData // one agent should serve only one specific user at a time knockUserMutex sync.RWMutex @@ -102,7 +102,7 @@ type UdpAgent struct { } type UdpConn struct { - ConnData *nhp.ConnectionData + ConnData *core.ConnectionData netConn *net.UDPConn } @@ -139,7 +139,7 @@ func (a *UdpAgent) Start(dirPath string, logLevel int) (err error) { return fmt.Errorf("private key parse error %v", err) } - a.device = nhp.NewDevice(nhp.NHP_AGENT, prk, nil) + a.device = core.NewDevice(core.NHP_AGENT, prk, nil) if a.device == nil { log.Critical("failed to create device %v\n", err) return fmt.Errorf("failed to create device %v", err) @@ -161,7 +161,7 @@ func (a *UdpAgent) Start(dirPath string, logLevel int) (err error) { a.loadResources() a.recvMsgCh = a.device.DecryptedMsgQueue - a.sendMsgCh = make(chan *nhp.MsgData, nhp.SendQueueSize) + a.sendMsgCh = make(chan *core.MsgData, core.SendQueueSize) // start agent routines a.wg.Add(2) @@ -247,15 +247,15 @@ func (a *UdpAgent) newConnection(addr *net.UDPAddr) (conn *UdpConn) { log.Info("Dial up new UDP connection from %s to %s", localAddr.String(), addr.String()) - conn.ConnData = &nhp.ConnectionData{ + conn.ConnData = &core.ConnectionData{ Device: a.device, - CookieStore: &nhp.CookieStore{}, - RemoteTransactionMap: make(map[uint64]*nhp.RemoteTransaction), + CookieStore: &core.CookieStore{}, + RemoteTransactionMap: make(map[uint64]*core.RemoteTransaction), LocalAddr: localAddr, RemoteAddr: addr, TimeoutMs: DefaultConnectionTimeoutMs, - SendQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), - RecvQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), + SendQueue: make(chan *core.Packet, PacketQueueSizePerConnection), + RecvQueue: make(chan *core.Packet, PacketQueueSizePerConnection), BlockSignal: make(chan struct{}), SetTimeoutSignal: make(chan struct{}), StopSignal: make(chan struct{}), @@ -319,21 +319,21 @@ func (a *UdpAgent) sendMessageRoutine() { } -func (a *UdpAgent) SendPacket(pkt *nhp.UdpPacket, conn *UdpConn) (n int, err error) { +func (a *UdpAgent) SendPacket(pkt *core.Packet, conn *UdpConn) (n int, err error) { defer func() { atomic.AddUint64(&a.stats.totalSendBytes, uint64(n)) atomic.StoreInt64(&conn.ConnData.LastLocalSendTime, time.Now().UnixNano()) if !pkt.KeepAfterSend { - a.device.ReleaseUdpPacket(pkt) + a.device.ReleasePoolPacket(pkt) } }() - pktType := nhp.HeaderTypeToString(pkt.HeaderType) - //log.Debug("Send [%s] packet (%s -> %s): %+v", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Packet) - log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - log.Evaluate("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - return conn.netConn.Write(pkt.Packet) + pktType := core.HeaderTypeToString(pkt.HeaderType) + //log.Debug("Send [%s] packet (%s -> %s): %+v", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Content) + log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + log.Evaluate("Send [%s] packet (%s -> %s), %d bytes", pktType, conn.ConnData.LocalAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + return conn.netConn.Write(pkt.Content) } func (a *UdpAgent) recvPacketRoutine(conn *UdpConn) { @@ -353,10 +353,10 @@ func (a *UdpAgent) recvPacketRoutine(conn *UdpConn) { } // udp recv, blocking until packet arrives or netConn.Close() - pkt := a.device.AllocateUdpPacket() + pkt := a.device.AllocatePoolPacket() n, err := conn.netConn.Read(pkt.Buf[:]) if err != nil { - a.device.ReleaseUdpPacket(pkt) + a.device.ReleasePoolPacket(pkt) if n == 0 { // udp connection closed, it is not an error return @@ -369,21 +369,21 @@ func (a *UdpAgent) recvPacketRoutine(conn *UdpConn) { atomic.AddUint64(&a.stats.totalRecvBytes, uint64(n)) // check minimal length - if n < nhp.HeaderSize { - a.device.ReleaseUdpPacket(pkt) + if n < core.HeaderSize { + a.device.ReleasePoolPacket(pkt) log.Error("Received UDP packet from %s is too short, discard", addrStr) continue } - pkt.Packet = pkt.Buf[:n] - //log.Trace("receive udp packet (%s -> %s): %+v", conn.ConnData.RemoteAddr.String(), conn.ConnData.LocalAddr.String(), pkt.Packet) + pkt.Content = pkt.Buf[:n] + //log.Trace("receive udp packet (%s -> %s): %+v", conn.ConnData.RemoteAddr.String(), conn.ConnData.LocalAddr.String(), pkt.Content) typ, _, err := a.device.RecvPrecheck(pkt) - msgType := nhp.HeaderTypeToString(typ) + msgType := core.HeaderTypeToString(typ) log.Info("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, conn.ConnData.LocalAddr.String(), n) log.Evaluate("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, conn.ConnData.LocalAddr.String(), n) if err != nil { - a.device.ReleaseUdpPacket(pkt) + a.device.ReleasePoolPacket(pkt) log.Warning("Receive [%s] packet (%s -> %s), precheck error: %v", msgType, addrStr, conn.ConnData.LocalAddr.String(), err) log.Evaluate("Receive [%s] packet (%s -> %s) precheck error: %v", msgType, addrStr, conn.ConnData.LocalAddr.String(), err) continue @@ -444,11 +444,11 @@ func (a *UdpAgent) connectionRoutine(conn *UdpConn) { if pkt == nil { continue } - log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Packet), addrStr) + log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Content), addrStr) // process keepalive packet - if pkt.HeaderType == nhp.NHP_KPL { - a.device.ReleaseUdpPacket(pkt) + if pkt.HeaderType == core.NHP_KPL { + a.device.ReleasePoolPacket(pkt) log.Info("Receive [NHP_KPL] message (%s -> %s)", addrStr, conn.ConnData.LocalAddr.String()) continue } @@ -463,7 +463,7 @@ func (a *UdpAgent) connectionRoutine(conn *UdpConn) { } } - pd := &nhp.PacketData{ + pd := &core.PacketData{ BasePacket: pkt, ConnData: conn.ConnData, InitTime: atomic.LoadInt64(&conn.ConnData.LastLocalRecvTime), @@ -498,7 +498,7 @@ func (a *UdpAgent) recvMessageRoutine() { } switch ppd.HeaderType { - case nhp.NHP_COK: + case core.NHP_COK: // synchronously block and deal with cookie message to ensure future messages will be correctly processed. note cookie is not handled as a transaction, so it arrives in here a.HandleCookieMessage(ppd) @@ -581,8 +581,8 @@ func (a *UdpAgent) knockResourceRoutine() { } } -func (a *UdpAgent) AddServer(server *nhp.UdpPeer) { - if server.DeviceType() == nhp.NHP_SERVER { +func (a *UdpAgent) AddServer(server *core.UdpPeer) { + if server.DeviceType() == core.NHP_SERVER { a.device.AddPeer(server) a.serverPeerMutex.Lock() a.serverPeerMap[server.PublicKeyBase64()] = server @@ -647,7 +647,7 @@ func (a *UdpAgent) RemoveResource(aspId string, resId string) { } } -func (a *UdpAgent) FindServerPeerFromResource(res *KnockResource) *nhp.UdpPeer { +func (a *UdpAgent) FindServerPeerFromResource(res *KnockResource) *core.UdpPeer { a.serverPeerMutex.Lock() defer a.serverPeerMutex.Unlock() for _, peer := range a.serverPeerMap { @@ -660,7 +660,7 @@ func (a *UdpAgent) FindServerPeerFromResource(res *KnockResource) *nhp.UdpPeer { } // if the server uses hostname as destination, find the correct peer with the actual IP address -func (a *UdpAgent) ResolvePeer(peer *nhp.UdpPeer) (*nhp.UdpPeer, net.Addr) { +func (a *UdpAgent) ResolvePeer(peer *core.UdpPeer) (*core.UdpPeer, net.Addr) { addr := peer.SendAddr() if addr == nil { return peer, nil diff --git a/build.bat b/build.bat index eb0b3c89..df7a3807 100644 --- a/build.bat +++ b/build.bat @@ -17,6 +17,7 @@ echo build time: %BUILD_TIME% set LD_FLAGS="-X 'github.com/OpenNHP/opennhp/version.Version=%VERSION%' -X 'github.com/OpenNHP/opennhp/version.CommitId=%COMMIT_ID%' -X 'github.com/OpenNHP/opennhp/version.CommitTime=%COMMIT_TIME%' -X 'github.com/OpenNHP/opennhp/version.BuildTime=%BUILD_TIME%'" go mod tidy +set CGO_ENABLED=1 :agentd go build -trimpath -ldflags %LD_FLAGS% -v -o release\nhp-agent\nhp-agentd.exe agent\main\main.go @@ -39,4 +40,14 @@ IF %ERRORLEVEL% NEQ 0 exit /b 1 gcc agent\sdkdemo\nhp-agent-demo.c -I release\nhp-agent -l:nhp-agent.dll -Lrelease\nhp-agent -Wl,-rpath=. -o release\nhp-agent\nhp-agent-demo.exe IF %ERRORLEVEL% NEQ 0 exit /b 1 +:devicesdk +go build -trimpath -buildmode=c-shared -ldflags %LD_FLAGS% -v -o release\nhp-device\nhpdevice.dll nhp\main\main.go nhp\main\nhpdevice.go +IF %ERRORLEVEL% NEQ 0 exit /b 1 +gcc nhp\sdkdemo\nhp-device-demo.c -I nhp\main -I release\nhp-device -l:nhpdevice.dll -Lrelease\nhp-device -Wl,-rpath=. -o release\nhp-device\nhp-device-demo.exe +IF %ERRORLEVEL% NEQ 0 exit /b 1 +cd release\nhp-device +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 +lib /def:./nhpdevice.def /name:nhpdevice.dll /out:./nhpdevice.lib /MACHINE:X64 +cd ..\.. + echo [Done] OpenNHP v%VERSION% for platform %OS% built! \ No newline at end of file diff --git a/common/errors.go b/common/errors.go index cd45ff74..970c0f96 100644 --- a/common/errors.go +++ b/common/errors.go @@ -1,6 +1,9 @@ package common -import "strings" +import ( + "strconv" + "strings" +) var errorMap map[string]*Error = make(map[string]*Error) @@ -12,7 +15,7 @@ type Error struct { msgCH string } -// implment error interface +// implment NhpError interface func (e *Error) Error() string { switch strings.ToUpper(ErrorMsgLanguageLocale) { case "EN", "EN-US", "EN-GB": @@ -27,6 +30,11 @@ func (e *Error) ErrorCode() string { return e.code } +func (e *Error) ErrorNumber() int { + n, _ := strconv.Atoi(e.code) + return n +} + func newError(code string, enStr string, chStr string) *Error { e := &Error{ code: code, @@ -61,6 +69,7 @@ func ErrorCodeToError(code string) *Error { return nil // should not happen } +// application errors var ( // generic ErrSuccess = newError("0", "", "") diff --git a/nhp/benchmark/ecc_rsa_test.go b/core/benchmark/ecc_rsa_test.go similarity index 75% rename from nhp/benchmark/ecc_rsa_test.go rename to core/benchmark/ecc_rsa_test.go index 4c4b5a8b..730121b9 100644 --- a/nhp/benchmark/ecc_rsa_test.go +++ b/core/benchmark/ecc_rsa_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" ) var aeadCount uint64 = 0 @@ -47,8 +47,8 @@ func TestECCSharedKey(t *testing.T) { " and install a pre-built Qt for Windows, follow the instructions on the Getting Started with Qt page." for i := 0; i < 10; i++ { - ecdh := nhp.NewECDH(nhp.ECC_CURVE25519) - ecdhr := nhp.NewECDH(nhp.ECC_CURVE25519) + ecdh := core.NewECDH(core.ECC_CURVE25519) + ecdhr := core.NewECDH(core.ECC_CURVE25519) ssc := ecdh.SharedSecret(ecdhr.PublicKey()) sss := ecdhr.SharedSecret(ecdh.PublicKey()) @@ -58,18 +58,27 @@ func TestECCSharedKey(t *testing.T) { // return //} - hash := sha256.New() - hash.Write(ssc[:]) - hashed := hash.Sum(nil) - aeadc := nhp.AeadFromKey(nhp.GCM_AES256, ssc) - aeads := nhp.AeadFromKey(nhp.GCM_AES256, sss) + var sscKey, sssKey [core.SymmetricKeySize]byte + copy(sscKey[:], ssc[:]) + copy(sssKey[:], sss[:]) + + hashc := sha256.New() + hashc.Write(ssc[:]) + hashedc := hashc.Sum(nil) + + hashs := sha256.New() + hashs.Write(ssc[:]) + hasheds := hashs.Sum(nil) + + aeadc := core.AeadFromKey(core.GCM_AES256, &sscKey) + aeads := core.AeadFromKey(core.GCM_AES256, &sssKey) var nonceBytes [12]byte aeadCount++ binary.BigEndian.PutUint64(nonceBytes[:], aeadCount) - encrypted := aeadc.Seal(nil, nonceBytes[:], []byte(msg), hashed) - decrypted, err := aeads.Open(nil, nonceBytes[:], encrypted, hashed) + encrypted := aeadc.Seal(nil, nonceBytes[:], []byte(msg), hashedc) + decrypted, err := aeads.Open(nil, nonceBytes[:], encrypted, hasheds) _ = decrypted if err != nil { fmt.Printf("aead decrypt error: %v", err) @@ -90,8 +99,8 @@ func TestGMSharedKey(t *testing.T) { " and install a pre-built Qt for Windows, follow the instructions on the Getting Started with Qt page." for i := 0; i < 10; i++ { - ecdh := nhp.NewECDH(nhp.ECC_SM2) - ecdhr := nhp.NewECDH(nhp.ECC_SM2) + ecdh := core.NewECDH(core.ECC_SM2) + ecdhr := core.NewECDH(core.ECC_SM2) ssc := ecdh.SharedSecret(ecdhr.PublicKey()) sss := ecdhr.SharedSecret(ecdh.PublicKey()) @@ -101,18 +110,27 @@ func TestGMSharedKey(t *testing.T) { // return //} - hash := sha256.New() - hash.Write(ssc[:]) - hashed := hash.Sum(nil) - aeadc := nhp.AeadFromKey(nhp.GCM_SM4, ssc) - aeads := nhp.AeadFromKey(nhp.GCM_SM4, sss) + var sscKey, sssKey [core.SymmetricKeySize]byte + copy(sscKey[:], ssc[:]) + copy(sssKey[:], sss[:]) + + hashc := sha256.New() + hashc.Write(ssc[:]) + hashedc := hashc.Sum(nil) + + hashs := sha256.New() + hashs.Write(ssc[:]) + hasheds := hashs.Sum(nil) + + aeadc := core.AeadFromKey(core.GCM_SM4, &sscKey) + aeads := core.AeadFromKey(core.GCM_SM4, &sssKey) var nonceBytes [12]byte aeadCount++ binary.BigEndian.PutUint64(nonceBytes[:], aeadCount) - encrypted := aeadc.Seal(nil, nonceBytes[:], []byte(msg), hashed) - decrypted, err := aeads.Open(nil, nonceBytes[:], encrypted, hashed) + encrypted := aeadc.Seal(nil, nonceBytes[:], []byte(msg), hashedc) + decrypted, err := aeads.Open(nil, nonceBytes[:], encrypted, hasheds) _ = decrypted if err != nil { fmt.Printf("aead decrypt error: %v", err) diff --git a/nhp/benchmark/rsa_utils.go b/core/benchmark/rsa_utils.go similarity index 100% rename from nhp/benchmark/rsa_utils.go rename to core/benchmark/rsa_utils.go diff --git a/nhp/constants.go b/core/constants.go similarity index 99% rename from nhp/constants.go rename to core/constants.go index 02c443a8..2fe9ff07 100644 --- a/nhp/constants.go +++ b/core/constants.go @@ -1,4 +1,4 @@ -package nhp +package core // protocol const ProtocolVersionMajor = 1 diff --git a/core/crypto.go b/core/crypto.go new file mode 100644 index 00000000..b7647204 --- /dev/null +++ b/core/crypto.go @@ -0,0 +1,242 @@ +package core + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha256" + "fmt" + "hash" + + "github.com/emmansun/gmsm/padding" + "github.com/emmansun/gmsm/sm3" + "github.com/emmansun/gmsm/sm4" + "golang.org/x/crypto/blake2s" + "golang.org/x/crypto/chacha20poly1305" + + "github.com/OpenNHP/opennhp/core/scheme/curve" + "github.com/OpenNHP/opennhp/core/scheme/gmsm" +) + +type HashTypeEnum int + +const ( + HASH_BLAKE2S HashTypeEnum = iota + HASH_SM3 + HASH_SHA256 +) + +type EccTypeEnum int + +const ( + ECC_CURVE25519 EccTypeEnum = iota + ECC_SM2 + ECC_UMI +) + +type GcmTypeEnum int + +const ( + GCM_AES256 GcmTypeEnum = iota + GCM_SM4 + GCM_CHACHA20POLY1305 +) + +type CipherSuite struct { + Scheme int + EccType EccTypeEnum + HashType HashTypeEnum + GcmType GcmTypeEnum +} + +const ( + CIPHER_SCHEME_CURVE int = iota + CIPHER_SCHEME_GMSM +) + +// init cipher suite +func NewCipherSuite(scheme int) (ciphers *CipherSuite) { + // init cipher suite + switch scheme { + case CIPHER_SCHEME_CURVE: + ciphers = &CipherSuite{ + Scheme: CIPHER_SCHEME_CURVE, + HashType: HASH_BLAKE2S, + EccType: ECC_CURVE25519, + GcmType: GCM_AES256, + } + + case CIPHER_SCHEME_GMSM: + fallthrough + default: + ciphers = &CipherSuite{ + Scheme: CIPHER_SCHEME_GMSM, + HashType: HASH_SM3, + EccType: ECC_SM2, + GcmType: GCM_SM4, + } + } + return +} + +func NewHash(t HashTypeEnum) (h hash.Hash) { + switch t { + case HASH_BLAKE2S: + h, _ = blake2s.New256(nil) + + case HASH_SM3: + h = sm3.New() + + case HASH_SHA256: + h = sha256.New() + } + + return h +} + +type Ecdh interface { + SetPrivateKey(prk []byte) error + PrivateKey() []byte + PublicKey() []byte + SharedSecret(pbk []byte) []byte + Name() string + PrivateKeyBase64() string + PublicKeyBase64() string + Identity() []byte + MidPublicKey() []byte +} + +func ECDHFromKey(t EccTypeEnum, prk []byte) (e Ecdh) { + switch t { + case ECC_CURVE25519: + var c curve.Curve25519ECDH + err := c.SetPrivateKey(prk) + if err != nil { + return nil + } + e = &c + + case ECC_SM2: + var s gmsm.SM2ECDH + err := s.SetPrivateKey(prk) + if err != nil { + return nil + } + e = &s + } + + return e +} + +func NewECDH(t EccTypeEnum) (e Ecdh) { + switch t { + case ECC_CURVE25519: + e = curve.NewECDH() + + case ECC_SM2: + e = gmsm.NewECDH() + } + + return e +} + +func AeadFromKey(t GcmTypeEnum, key *[SymmetricKeySize]byte) (aead cipher.AEAD) { + switch t { + case GCM_AES256: + aesBlock, _ := aes.NewCipher(key[:]) + aead, _ = cipher.NewGCM(aesBlock) + + case GCM_SM4: + sm4Block, _ := sm4.NewCipher(key[:16]) + aead, _ = cipher.NewGCM(sm4Block) + + case GCM_CHACHA20POLY1305: + aead, _ = chacha20poly1305.New(key[:]) + } + + return aead +} + +func CBCEncryption(t GcmTypeEnum, key *[SymmetricKeySize]byte, plaintext []byte, inPlace bool) ([]byte, error) { + var block cipher.Block + var iv []byte + switch t { + case GCM_AES256: + block, _ = aes.NewCipher(key[:]) + iv = key[8:24] + + case GCM_SM4: + block, _ = sm4.NewCipher(key[:16]) + iv = key[16:] + + case GCM_CHACHA20POLY1305: + return nil, ErrNotApplicable + } + + var paddedPlainText []byte + if len(plaintext)%block.BlockSize() == 0 { + // skip padding + paddedPlainText = plaintext + } else { + pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize())) + paddedPlainText = pkcs7.Pad(plaintext) + } + + var ciphertext []byte + if inPlace { + ciphertext = paddedPlainText + } else { + ciphertext = make([]byte, 0, len(plaintext)) + } + + mode := cipher.NewCBCEncrypter(block, iv) + // CryptBlocks can work in-place if the two arguments are the same. + mode.CryptBlocks(ciphertext, paddedPlainText) + + return ciphertext, nil +} + +func CBCDecryption(t GcmTypeEnum, key *[SymmetricKeySize]byte, ciphertext []byte, inPlace bool) ([]byte, error) { + var block cipher.Block + var iv []byte + var err error + switch t { + case GCM_AES256: + block, _ = aes.NewCipher(key[:]) + iv = key[8:24] + + case GCM_SM4: + block, _ = sm4.NewCipher(key[:16]) + iv = key[16:] + + case GCM_CHACHA20POLY1305: + return nil, ErrNotApplicable + } + + if len(ciphertext) < block.BlockSize() { + return nil, fmt.Errorf("ciphertext too short") + } + + var plaintext []byte + if inPlace { + plaintext = ciphertext + } else { + plaintext = make([]byte, len(ciphertext)) + } + + mode := cipher.NewCBCDecrypter(block, iv) + // CryptBlocks can work in-place if the two arguments are the same. + mode.CryptBlocks(plaintext, ciphertext) + + if len(plaintext)%block.BlockSize() == 0 { + // skip unpadding + } else { + // Unpad plaintext + pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize())) + plaintext, err = pkcs7.Unpad(plaintext) + if err != nil { + return nil, err + } + } + + return plaintext, nil +} diff --git a/nhp/device.go b/core/device.go similarity index 80% rename from nhp/device.go rename to core/device.go index 49f00d63..ea70cf84 100644 --- a/nhp/device.go +++ b/core/device.go @@ -1,10 +1,13 @@ -package nhp +package core import ( "encoding/base64" + "fmt" "runtime" + "runtime/debug" "sync" "sync/atomic" + "time" "github.com/OpenNHP/opennhp/log" ) @@ -26,6 +29,12 @@ type DeviceOptions struct { DisableRelayPeerValidation bool } +type NhpError interface { + Error() string + ErrorCode() string + ErrorNumber() int +} + func defaultDeviceOptions(t int) (option DeviceOptions) { switch t { case NHP_AGENT: @@ -43,10 +52,10 @@ type Device struct { optionMutex sync.Mutex option DeviceOptions - counterIndex uint64 - deviceType int - staticEcdh Ecdh - staticEcdhEx Ecdh + counterIndex uint64 + deviceType int + staticEcdhCurve Ecdh // for cipherscheme curve + staticEcdhGmsm Ecdh // for cipherscheme gmsm peerMapMutex sync.Mutex peerMap map[string]Peer @@ -78,13 +87,13 @@ func NewDevice(t int, prk []byte, option *DeviceOptions) *Device { d.option = defaultDeviceOptions(t) } - d.staticEcdh = ECDHFromKey(ECC_CURVE25519, prk) - if d.staticEcdh == nil { + d.staticEcdhCurve = ECDHFromKey(ECC_CURVE25519, prk) + if d.staticEcdhCurve == nil { log.Critical("Failed to set private key") return nil } - d.staticEcdhEx = ECDHFromKey(ECC_SM2, prk) - if d.staticEcdhEx == nil { + d.staticEcdhGmsm = ECDHFromKey(ECC_SM2, prk) + if d.staticEcdhGmsm == nil { log.Critical("Failed to set private key ex") return nil } @@ -128,17 +137,18 @@ func (d *Device) Stop() { } func (d *Device) PublicKeyBase64() string { - return d.staticEcdh.PublicKeyBase64() + return d.staticEcdhCurve.PublicKeyBase64() } func (d *Device) PublicKeyExBase64() string { - return d.staticEcdhEx.PublicKeyBase64() + return d.staticEcdhGmsm.PublicKeyBase64() } func (d *Device) NextCounterIndex() uint64 { return atomic.AddUint64(&d.counterIndex, 1) } +// 异步多通道处理 func (d *Device) msgToPacketRoutine(id int) { defer d.wg.Done() defer log.Info("msgToPacketRoutine %d: quit", id) @@ -234,7 +244,7 @@ func (d *Device) msgToPacketRoutine(id int) { transactionId: mad.header.Counter(), connData: mad.connData, mad: mad, - NextPacketCh: make(chan *UdpPacket), + NextPacketCh: make(chan *Packet), timeout: d.LocalTransactionTimeout(), } d.AddLocalTransaction(t) @@ -247,6 +257,53 @@ func (d *Device) msgToPacketRoutine(id int) { } } +// 同步线性处理 +func (d *Device) MsgToPacket(md *MsgData) (mad *MsgAssemblerData, err error) { + defer func() { + if x := recover(); x != nil { + mad = nil + err = fmt.Errorf("!!!recovered from panic: %v\n%s", x, string(debug.Stack())) + ErrRuntimePanic.SetExtraError(err) + err = ErrRuntimePanic + } + }() + + var buf [PacketBufferSize]byte + md.ExternalPacket = &Packet{ + Buf: &buf, + Content: buf[:], + HeaderType: md.HeaderType, + } + //md.Compress = len(md.Message) > 64 // no gain for compression if size is small + // use new transaction id if not specified + if md.TransactionId == 0 { + md.TransactionId = d.NextCounterIndex() + } + + // process keepalive separately + if md.HeaderType == NHP_KPL { + mad, _ = d.createKeepalivePacket(md) + return mad, nil + } + + mad, err = d.createMsgAssemblerData(md) + defer mad.Destroy() + if err != nil { + return nil, err + } + err = mad.setPeerPublicKey(nil) + if err != nil { + return nil, err + } + err = mad.encryptBody() + if err != nil { + return nil, err + } + + return mad, nil +} + +// 异步多通道处理 func (d *Device) packetToMsgRoutine(id int) { defer d.wg.Done() defer log.Info("packetToMsgRoutine %d: quit", id) @@ -335,7 +392,7 @@ func (d *Device) packetToMsgRoutine(id int) { // start and save responder transaction if d.IsTransactionRequest(ppd.HeaderType) { t := &RemoteTransaction{ - transactionId: ppd.SenderId, + transactionId: ppd.SenderTrxId, connData: ppd.ConnData, parserData: ppd, // ppd is owned and to be destroyed by transaction NextMsgCh: make(chan *MsgData), @@ -359,6 +416,45 @@ func (d *Device) packetToMsgRoutine(id int) { } } +// 同步线性处理 +func (d *Device) PacketToMsg(pd *PacketData) (ppd *PacketParserData, err error) { + defer func() { + if x := recover(); x != nil { + ppd = nil + err = fmt.Errorf("!!!recovered from panic: %v\n%s", x, string(debug.Stack())) + ErrRuntimePanic.SetExtraError(err) + err = ErrRuntimePanic + } + }() + + var packetType int + packetType, _, err = d.RecvPrecheck(pd.BasePacket) + if err != nil { + return nil, err + } + // skip processing keepalive packet + if packetType == NHP_KPL { + return &PacketParserData{HeaderType: NHP_KPL}, nil + } + + pd.InitTime = time.Now().UnixNano() + ppd, err = d.createPacketParserData(pd) + defer ppd.Destroy() + if err != nil { + return nil, err + } + err = ppd.validatePeer() + if err != nil { + return nil, err + } + err = ppd.decryptBody() + if err != nil { + return nil, err + } + + return ppd, nil +} + func (d *Device) SendMsgToPacket(md *MsgData) { select { case d.msgToPacketQueue <- md: @@ -413,35 +509,6 @@ func (d *Device) LookupPeer(pk []byte) Peer { return nil } -func (d *Device) CheckRecvHeaderType(t int) bool { - // NHP_KPL is handled elsewhere - switch d.deviceType { - case NHP_AGENT: - switch t { - case NHP_ACK, NHP_LRT, NHP_COK, NHP_RAK: - return true - } - case NHP_SERVER: - switch t { - case NHP_REG, NHP_KNK, NHP_LST, NHP_RKN, NHP_EXT, NHP_ART, NHP_RLY, NHP_AOL, NHP_OTP: - return true - } - case NHP_AC: - switch t { - case NHP_AOP, NHP_LRT, NHP_AAK: - return true - } - case NHP_RELAY: - switch t { - case NHP_REG, NHP_KNK, NHP_ACK, NHP_LST, NHP_LRT, NHP_COK, NHP_RKN, NHP_EXT: - return true - } - } - - log.Info("Device type: %d, recv header type %d not allowed", d.deviceType, t) - return false -} - func (d *Device) IsOverload() bool { //return true // debug return d.Overload.Load() diff --git a/core/errors.go b/core/errors.go new file mode 100644 index 00000000..e6e5905d --- /dev/null +++ b/core/errors.go @@ -0,0 +1,113 @@ +package core + +/* +#include "main/nhpdevicedef.h" +*/ +import "C" +import ( + "strconv" +) + +var errorMap map[int]*Error = make(map[int]*Error) + +type Error struct { + num int + msg string + extraErr error + hasExtraErr bool +} + +func (e *Error) SetExtraError(err error) { + e.extraErr = err + if err != nil { + e.hasExtraErr = true + } +} + +// implment NhpError interface +func (e *Error) Error() string { + if e.hasExtraErr { + e.hasExtraErr = false + defer e.SetExtraError(nil) + return e.msg + ": " + e.extraErr.Error() + } + return e.msg +} + +func (e *Error) ErrorCode() string { + return strconv.Itoa(e.num) +} + +func (e *Error) ErrorNumber() int { + return e.num +} + +func newError(number C.int, msg string) *Error { + e := &Error{ + num: int(number), + msg: msg, + } + errorMap[e.num] = e + return e +} + +func ErrorToErrorNumber(err error) int { + e, ok := err.(*Error) + if ok { + return e.ErrorNumber() + } + return -1 +} + +func ErrorToString(err error) string { + e, ok := err.(*Error) + if ok { + return e.Error() + } + return "" +} + +func ErrorCodeToError(number int) *Error { + e, found := errorMap[number] + if found { + return e + } + return nil // should not happen +} + +// device sdk errors +var ( + ErrSuccess = newError(C.ERR_NHP_SUCCESS, "") + + // device + ErrCipherNotSupported = newError(C.ERR_NHP_CIPHER_NOT_SUPPORTED, "cipher scheme not supported") + ErrNotApplicable = newError(C.ERR_NHP_OPERATION_NOT_APPLICABLE, "operation not applicable") + ErrCreateDeviceFailed = newError(C.ERR_NHP_CREATE_DEVICE_FAILED, "failed to create nhp device") + ErrCloseDeviceFailed = newError(C.ERR_NHP_CLOSE_DEVICE_FAILED, "attempt to close a non-initialized nhp device") + ErrRuntimePanic = newError(C.ERR_NHP_SDK_RUNTIME_PANIC, "runtime panic encountered") + + // initiator and encryption + ErrEmptyPeerPublicKey = newError(C.ERR_NHP_EMPTY_PEER_PUBLIC_KEY, "remote peer public key is not set") + ErrEphermalECDHPeerFailed = newError(C.ERR_NHP_EPHERMAL_ECDH_PEER_FAILED, "ephermal ECDH failed with peer") + ErrDeviceECDHPeerFailed = newError(C.ERR_NHP_DEVICE_ECDH_PEER_FAILED, "device ECDH failed with peer") + ErrIdentityTooLong = newError(C.ERR_NHP_IDENTITY_TOO_LONG, "identity exceeds max length") + ErrDataCompressionFailed = newError(C.ERR_NHP_DATA_COMPRESSION_FAILED, "data compression failed") + ErrPacketSizeExceedsBuffer = newError(C.ERR_NHP_PACKET_SIZE_EXCEEDS_BUFFER, "packet size longer than send buffer") + + // responder and decryption + ErrCloseConnection = newError(C.ERR_NHP_CLOSE_CONNECTION, "disengage nhp access immediately") + ErrIncorrectPacketSize = newError(C.ERR_NHP_INCORRECT_PACKET_SIZE, "incorrect packet size") + ErrMessageTypeNotMatchDevice = newError(C.ERR_NHP_MESSAGE_TYPE_NOT_MATCH_DEVICE, "message type does not match device") + ErrServerOverload = newError(C.ERR_NHP_SERVER_OVERLOAD, "the packet is dropped due to server overload") + ErrHMACCheckFailed = newError(C.ERR_NHP_HMAC_CHECK_FAILED, "HMAC validation failed") + ErrServerHMACCheckFailed = newError(C.ERR_NHP_SERVER_HMAC_CHECK_FAILED, "server HMAC validation failed") + ErrDeviceECDHEphermalFailed = newError(C.ERR_NHP_DEVICE_ECDH_EPHERMAL_FAILED, "device ECDH failed with ephermal") + ErrPeerIdentityVerificationFailed = newError(C.ERR_NHP_PEER_IDENTITY_VERIFICATION_FAILED, "failed to verify peer's identity with apk") + ErrAEADDecryptionFailed = newError(C.ERR_NHP_AEAD_DECRYPTION_FAILED, "aead decryption failed") + ErrDataDecompressionFailed = newError(C.ERR_NHP_DATA_DECOMPRESSION_FAILED, "data decompression failed") + ErrDeviceECDHObtainedPeerFailed = newError(C.ERR_NHP_DEVICE_ECDH_OBTAINED_PEER_FAILED, "device ECDH failed with obtained peer") + ErrServerRejectWithCookie = newError(C.ERR_NHP_SERVER_REJECT_WITH_COOKIE, "server overload, stop processing packet and return cookie") + ErrReplayPacketReceived = newError(C.ERR_NHP_REPLAY_PACKET_RECEIVED, "received replay packet, drop") + ErrFloodPacketReceived = newError(C.ERR_NHP_FLOOD_PACKET_RECEIVED, "received flood packet, drop") + ErrStalePacketReceived = newError(C.ERR_NHP_STALE_PACKET_RECEIVED, "received stale packet, drop") +) diff --git a/nhp/initiator.go b/core/initiator.go similarity index 63% rename from nhp/initiator.go rename to core/initiator.go index f4c7d799..e3c77854 100644 --- a/nhp/initiator.go +++ b/core/initiator.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "bytes" @@ -11,23 +11,35 @@ import ( "time" "unsafe" + "github.com/OpenNHP/opennhp/core/scheme/curve" + "github.com/OpenNHP/opennhp/core/scheme/gmsm" "github.com/OpenNHP/opennhp/log" ) +type InitiatorScheme interface { + CreateMsgAssemblerData(d *Device, md *MsgData) (mad *MsgAssemblerData, err error) + DeriveMsgAssemblerDataFromPrevParserData(ppd *PacketParserData, t int, message []byte) (mad *MsgAssemblerData) + SetPeerPublicKey(d *Device, mad *MsgAssemblerData, peerPk []byte) (err error) + EncryptBody(d *Device, mad *MsgAssemblerData) (err error) +} + type MsgData struct { - RemoteAddr *net.UDPAddr // used by agent and door create a new connection or pick an existing connection for msg sending + RemoteAddr *net.UDPAddr // used by agent and ac create a new connection or pick an existing connection for msg sending ConnData *ConnectionData // used by server to pick an existing connection for msg sending PrevParserData *PacketParserData // when PrevParserData is set, RemoteAddr, ConnData, TransactionId and PeerPk will be overridden - HeaderType int + CipherScheme int // 0: curve25519/chacha20/blake2s, 1: sm2/sm4/sm3 TransactionId uint64 + HeaderType int Compress bool + ExternalPacket *Packet + ExternalCookie *[CookieSize]byte Message []byte PeerPk []byte EncryptedPktCh chan *MsgAssemblerData ResponseMsgCh chan *PacketParserData } -func (d *Device) ValidateMsgData(md *MsgData) (err error) { +func (d *Device) validateMsgData(md *MsgData) (err error) { if md.PrevParserData == nil { if d.deviceType == NHP_SERVER && md.ConnData == nil { err = fmt.Errorf("missing connection data for server") @@ -45,7 +57,7 @@ func (d *Device) ValidateMsgData(md *MsgData) (err error) { type MsgAssemblerData struct { device *Device - BasePacket *UdpPacket + BasePacket *Packet connData *ConnectionData ciphers *CipherSuite @@ -58,14 +70,17 @@ type MsgAssemblerData struct { chainKey [SymmetricKeySize]byte LocalInitTime int64 + TransactionId uint64 noise NoiseFactory // int + CipherScheme int HeaderType int BodySize int HeaderFlag uint16 BodyCompress bool - RemotePubKey []byte - bodyMessage []byte + ExternalCookie *[CookieSize]byte + RemotePubKey []byte + bodyMessage []byte encryptedPktCh chan<- *MsgAssemblerData ResponseMsgCh chan<- *PacketParserData @@ -79,34 +94,48 @@ func (d *Device) createMsgAssemblerData(md *MsgData) (mad *MsgAssemblerData, err } else { mad = &MsgAssemblerData{} mad.device = d + mad.CipherScheme = md.CipherScheme mad.HeaderType = md.HeaderType mad.RemotePubKey = md.PeerPk mad.BodyCompress = md.Compress - mad.bodyMessage = []byte(md.Message) + mad.bodyMessage = md.Message + mad.TransactionId = md.TransactionId mad.connData = md.ConnData mad.encryptedPktCh = md.EncryptedPktCh // init packet buffer - mad.BasePacket = d.AllocateUdpPacket() + if md.ExternalPacket != nil { + mad.BasePacket = md.ExternalPacket + } else { + mad.BasePacket = d.AllocatePoolPacket() + } mad.BasePacket.HeaderType = mad.HeaderType + // init cookie if specified + if md.ExternalCookie != nil { + mad.ExternalCookie = md.ExternalCookie + } + // create header and init device ecdh - useGm := len(mad.RemotePubKey) == PublicKeySizeEx - mad.ciphers = NewCipherSuite(useGm) - if useGm { - mad.HeaderFlag |= NHP_FLAG_EXTENDEDLENGTH - mad.header = (*NHPHeaderEx)(unsafe.Pointer(&mad.BasePacket.Buf[0])) - mad.deviceEcdh = d.staticEcdhEx - } else { - mad.header = (*NHPHeader)(unsafe.Pointer(&mad.BasePacket.Buf[0])) - mad.deviceEcdh = d.staticEcdh + switch mad.CipherScheme { + case CIPHER_SCHEME_CURVE: + mad.header = (*curve.HeaderCurve)(unsafe.Pointer(&mad.BasePacket.Buf[0])) + mad.ciphers = NewCipherSuite(CIPHER_SCHEME_CURVE) + mad.deviceEcdh = d.staticEcdhCurve + + case CIPHER_SCHEME_GMSM: + fallthrough + default: + mad.header = (*gmsm.HeaderGmsm)(unsafe.Pointer(&mad.BasePacket.Buf[0])) + mad.ciphers = NewCipherSuite(CIPHER_SCHEME_GMSM) + mad.deviceEcdh = d.staticEcdhGmsm } // init version mad.header.SetVersion(ProtocolVersionMajor, ProtocolVersionMinor) // init header counter - mad.header.SetCounter(md.TransactionId) + mad.header.SetCounter(mad.TransactionId) // init chain hash -> ChainHash0 mad.chainHash = NewHash(mad.ciphers.HashType) @@ -128,30 +157,35 @@ func (d *Device) createMsgAssemblerData(md *MsgData) (mad *MsgAssemblerData, err mad.hmacHash.Write([]byte(InitialHashString)) // create ephermeral key - mad.ephermeralEcdh = NewECDH(mad.ciphers.EccType) + ephermalEccType := mad.ciphers.EccType + mad.ephermeralEcdh = NewECDH(ephermalEccType) copy(mad.header.EphermeralBytes(), mad.ephermeralEcdh.PublicKey()) return mad, nil } -func (mad *MsgAssemblerData) derivePacketParserData(pkt *UdpPacket, initTime int64) (ppd *PacketParserData) { +func (mad *MsgAssemblerData) derivePacketParserData(pkt *Packet, initTime int64) (ppd *PacketParserData) { ppd = &PacketParserData{} ppd.device = mad.device ppd.basePacket = pkt + ppd.CipherScheme = mad.CipherScheme ppd.ConnData = mad.connData ppd.LocalInitTime = initTime ppd.feedbackMsgCh = mad.ResponseMsgCh // init header and init device ecdh - ppd.HeaderFlag = binary.BigEndian.Uint16(ppd.basePacket.Packet[10:12]) - if ppd.HeaderFlag&NHP_FLAG_EXTENDEDLENGTH == 0 { - ppd.header = (*NHPHeader)(unsafe.Pointer(&ppd.basePacket.Packet[0])) - ppd.Ciphers = NewCipherSuite(false) - ppd.deviceEcdh = ppd.device.staticEcdh - } else { - ppd.header = (*NHPHeaderEx)(unsafe.Pointer(&ppd.basePacket.Packet[0])) - ppd.Ciphers = NewCipherSuite(true) - ppd.deviceEcdh = ppd.device.staticEcdhEx + ppd.HeaderFlag = binary.BigEndian.Uint16(ppd.basePacket.Content[10:12]) + switch mad.CipherScheme { + case CIPHER_SCHEME_CURVE: + ppd.header = (*curve.HeaderCurve)(unsafe.Pointer(&ppd.basePacket.Content[0])) + ppd.Ciphers = NewCipherSuite(CIPHER_SCHEME_CURVE) + ppd.deviceEcdh = ppd.device.staticEcdhCurve + case CIPHER_SCHEME_GMSM: + fallthrough + default: + ppd.header = (*gmsm.HeaderGmsm)(unsafe.Pointer(&ppd.basePacket.Content[0])) + ppd.Ciphers = NewCipherSuite(CIPHER_SCHEME_GMSM) + ppd.deviceEcdh = ppd.device.staticEcdhGmsm } // init chain hash -> ChainHash0 @@ -169,24 +203,26 @@ func (d *Device) createKeepalivePacket(md *MsgData) (mad *MsgAssemblerData, err mad = &MsgAssemblerData{} mad.device = d mad.HeaderType = NHP_KPL + mad.TransactionId = md.TransactionId mad.connData = md.ConnData // init packet buffer - mad.BasePacket = d.AllocateUdpPacket() + if md.ExternalPacket != nil { + mad.BasePacket = md.ExternalPacket + } else { + mad.BasePacket = d.AllocatePoolPacket() + } mad.BasePacket.HeaderType = NHP_KPL - mad.BasePacket.Packet = mad.BasePacket.Buf[:HeaderSize] + mad.BasePacket.Content = mad.BasePacket.Buf[:HeaderSize] // create header - mad.header = (*NHPHeader)(unsafe.Pointer(&mad.BasePacket.Buf[0])) + mad.header = (*curve.HeaderCurve)(unsafe.Pointer(&mad.BasePacket.Buf[0])) // init version mad.header.SetVersion(ProtocolVersionMajor, ProtocolVersionMinor) // init header counter - mad.header.SetCounter(md.TransactionId) - - // set header flag - mad.header.SetFlag(mad.HeaderFlag) + mad.header.SetCounter(mad.TransactionId) // set header type and payload size mad.header.SetTypeAndPayloadSize(mad.HeaderType, 0) @@ -202,7 +238,7 @@ func (mad *MsgAssemblerData) setPeerPublicKey(peerPk []byte) (err error) { if mad.RemotePubKey == nil { log.Error("remote peer public key is not set") - err = fmt.Errorf("remote peer public key is not set") + err = ErrEmptyPeerPublicKey return err } @@ -220,7 +256,7 @@ func (mad *MsgAssemblerData) setPeerPublicKey(peerPk []byte) (err error) { ess := mad.ephermeralEcdh.SharedSecret(mad.RemotePubKey) if ess == nil { log.Error("ephermal ECDH failed with peer") - err = fmt.Errorf("ephermal ECDH failed with peer") + err = ErrEphermalECDHPeerFailed return err } @@ -230,8 +266,19 @@ func (mad *MsgAssemblerData) setPeerPublicKey(peerPk []byte) (err error) { // generate gcm key and encrypt device pubkey ChainKey1 -> ChainKey2 (ChainKey5 -> ChainKey6) mad.noise.KeyGen2(&mad.chainKey, &key, mad.chainKey[:], ess[:]) SetZero(ess[:]) - aead := AeadFromKey(mad.ciphers.GcmType, &key) - static := aead.Seal(mad.header.StaticBytes()[:0], mad.header.NonceBytes(), mad.deviceEcdh.PublicKey(), mad.chainHash.Sum(nil)) + + var aead cipher.AEAD + var static []byte + // encrypt initiator's public key and evolve chainhash with the ciphertext + switch mad.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + aead = AeadFromKey(mad.ciphers.GcmType, &key) + static = aead.Seal(mad.header.StaticBytes()[:0], mad.header.NonceBytes(), mad.deviceEcdh.PublicKey(), mad.chainHash.Sum(nil)) + } // evolve chainhash ChainHash1 -> ChainHash2 mad.chainHash.Write(static) @@ -240,17 +287,27 @@ func (mad *MsgAssemblerData) setPeerPublicKey(peerPk []byte) (err error) { ss := mad.deviceEcdh.SharedSecret(mad.RemotePubKey) if ss == nil { log.Error("device ECDH failed with peer") - err = fmt.Errorf("device ECDH failed with peer") + err = ErrDeviceECDHPeerFailed return err } // generate gcm key and encrypt timestamp ChainKey2 -> ChainKey3 (ChainKey6 -> ChainKey7) mad.noise.KeyGen2(&mad.chainKey, &key, mad.chainKey[:], ss[:]) SetZero(ss[:]) + var tsBytes [TimestampSize]byte + var ts []byte binary.BigEndian.PutUint64(tsBytes[:], uint64(mad.LocalInitTime)) - aead = AeadFromKey(mad.ciphers.GcmType, &key) - ts := aead.Seal(mad.header.TimestampBytes()[:0], mad.header.NonceBytes(), tsBytes[:], mad.chainHash.Sum(nil)) + + switch mad.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + aead = AeadFromKey(mad.ciphers.GcmType, &key) + ts = aead.Seal(mad.header.TimestampBytes()[:0], mad.header.NonceBytes(), tsBytes[:], mad.chainHash.Sum(nil)) + } // evolve chainhash ChainHash2 -> ChainHash3 mad.chainHash.Write(ts) @@ -264,8 +321,10 @@ func (mad *MsgAssemblerData) setPeerPublicKey(peerPk []byte) (err error) { func (mad *MsgAssemblerData) encryptBody() (err error) { defer func() { + // clear secrets mad.chainHash.Reset() mad.chainHash = nil + SetZero(mad.chainKey[:]) }() // message body is empty, skip encryption. Set header and calculate HMAC @@ -274,7 +333,7 @@ func (mad *MsgAssemblerData) encryptBody() (err error) { mad.header.SetTypeAndPayloadSize(mad.HeaderType, 0) // set HMAC mad.addHMAC(mad.HeaderType == NHP_RKN) - mad.BasePacket.Packet = mad.BasePacket.Buf[:mad.header.Size()] + mad.BasePacket.Content = mad.BasePacket.Buf[:mad.header.Size()] return nil } @@ -289,10 +348,12 @@ func (mad *MsgAssemblerData) encryptBody() (err error) { w.Close() if err != nil { log.Critical("message compression failed: %v", err) + ErrDataCompressionFailed.SetExtraError(err) + err = ErrDataCompressionFailed return err } body = buf.Bytes() - mad.BodySize = len(body) + mad.BodySize = len(body) + GCMTagSize // set header flag mad.HeaderFlag |= NHP_FLAG_COMPRESS @@ -300,12 +361,12 @@ func (mad *MsgAssemblerData) encryptBody() (err error) { } else { // no compress body = mad.bodyMessage - mad.BodySize = len(mad.bodyMessage) + mad.BodySize = len(mad.bodyMessage) + GCMTagSize } - if mad.BodySize > PacketBufferSize-GCMTagSize-mad.header.Size() { + if mad.BodySize > PacketBufferSize-mad.header.Size() { log.Critical("message too long, send buffer exceeded") - err = fmt.Errorf("message longer than send buffer") + err = ErrPacketSizeExceedsBuffer return err } @@ -313,10 +374,10 @@ func (mad *MsgAssemblerData) encryptBody() (err error) { mad.header.SetFlag(mad.HeaderFlag) // calculate total data length - packetLen := mad.header.Size() + mad.BodySize + GCMTagSize + packetLen := mad.header.Size() + mad.BodySize // set header type and payload size - mad.header.SetTypeAndPayloadSize(mad.HeaderType, mad.BodySize+GCMTagSize) + mad.header.SetTypeAndPayloadSize(mad.HeaderType, mad.BodySize) // set HMAC mad.addHMAC(mad.HeaderType == NHP_RKN) @@ -325,7 +386,7 @@ func (mad *MsgAssemblerData) encryptBody() (err error) { mad.bodyAead.Seal(mad.BasePacket.Buf[mad.header.Size():mad.header.Size()], mad.header.NonceBytes(), body, mad.chainHash.Sum(nil)) // set valid packet - mad.BasePacket.Packet = mad.BasePacket.Buf[:packetLen] + mad.BasePacket.Content = mad.BasePacket.Buf[:packetLen] return nil } @@ -341,15 +402,20 @@ func (mad *MsgAssemblerData) addHMAC(sumCookie bool) { mad.hmacHash.Write(mad.header.Bytes()[0:len]) if sumCookie { - mad.connData.Lock() - mad.hmacHash.Write(mad.connData.CookieStore.Cookie[:]) - mad.connData.Unlock() + // use specified cookie, otherwise use connection's cookie + if mad.ExternalCookie != nil { + mad.hmacHash.Write((*mad.ExternalCookie)[:]) + } else { + mad.connData.Lock() + mad.hmacHash.Write(mad.connData.CookieStore.CurrCookie[:]) + mad.connData.Unlock() + } } mad.hmacHash.Sum(mad.header.HMACBytes()[:0]) } func (mad *MsgAssemblerData) Destroy() { - mad.device.ReleaseUdpPacket(mad.BasePacket) + mad.device.ReleasePoolPacket(mad.BasePacket) if mad.hmacHash != nil { mad.hmacHash.Reset() mad.hmacHash = nil @@ -358,5 +424,4 @@ func (mad *MsgAssemblerData) Destroy() { mad.chainHash.Reset() mad.chainHash = nil } - SetZero(mad.chainKey[:]) } diff --git a/nhp/kdf.go b/core/kdf.go similarity index 99% rename from nhp/kdf.go rename to core/kdf.go index 2577594a..ade3296a 100644 --- a/nhp/kdf.go +++ b/core/kdf.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "crypto/hmac" diff --git a/core/main/main.go b/core/main/main.go new file mode 100644 index 00000000..af1bd286 --- /dev/null +++ b/core/main/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("this is a demo program") +} diff --git a/core/main/nhpdevice.go b/core/main/nhpdevice.go new file mode 100644 index 00000000..1fedea58 --- /dev/null +++ b/core/main/nhpdevice.go @@ -0,0 +1,320 @@ +package main + +/* +#include "nhpdevicedef.h" +*/ +import "C" + +import ( + "encoding/base64" + "fmt" + "unsafe" + + "github.com/OpenNHP/opennhp/core" +) + +var devices map[string]*core.Device = make(map[string]*core.Device) +var handles map[uintptr]*core.Device = make(map[uintptr]*core.Device) + +// 释放NHPSDK产生的字符串缓冲区内存 +// +//export nhp_free_cstring +func nhp_free_cstring(ptr *C.char) { + C.free(unsafe.Pointer(ptr)) +} + +// 释放NHPSDK产生的nhpresult结构体缓冲区内存 +// +//export nhp_free_NhpResult +func nhp_free_NhpResult(ptr *C.NhpResult) { + C.free(unsafe.Pointer(ptr.errMsg)) + C.free(unsafe.Pointer(ptr)) +} + +// 释放NHPSDK产生的NhpEncryptResult结构体缓冲区内存 +// +//export nhp_free_NhpEncryptResult +func nhp_free_NhpEncryptResult(ptr *C.NhpEncryptResult) { + C.free(unsafe.Pointer(ptr.errMsg)) + C.free(unsafe.Pointer(ptr.packet)) + C.free(unsafe.Pointer(ptr)) +} + +// 释放NHPSDK产生的NhpDecryptResult结构体缓冲区内存 +// +//export nhp_free_NhpDecryptResult +func nhp_free_NhpDecryptResult(ptr *C.NhpDecryptResult) { + C.free(unsafe.Pointer(ptr.errMsg)) + C.free(unsafe.Pointer(ptr.msgId)) + C.free(unsafe.Pointer(ptr.data)) + C.free(unsafe.Pointer(ptr)) +} + +// 初始化nhp_device实例 +// 输入: +// deviceType:此device所代表的NHP组件: 1: nhp-agent, 2: nhp-server, 3: nhp-ac +// privateKeyBase64: 私钥的base64编码 +// 返回: +// NhpResult指针: errCode 0: nhp device实例初始化成功; 非0:nhp device实例初始化失败, errMsg: 错误描述 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpResult函数 +// +//export nhp_device_init +func nhp_device_init(deviceType C.int, privateKeyBase64 string) *C.NhpResult { + resultPtr := (*C.NhpResult)(C.malloc(C.sizeof_NhpResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpResult) + + if _, found := devices[privateKeyBase64]; found { + resultPtr.errCode = C.ERR_NHP_DEVICE_ALREADY_CREATED + resultPtr.errMsg = C.CString("nhp device already created with the given key") + return resultPtr + } + + privateKey, err := base64.StdEncoding.DecodeString(privateKeyBase64) + if err != nil { + resultPtr.errCode = C.ERR_NHP_CREATE_DEVICE_FAILED + resultPtr.errMsg = C.CString("key invalid") + return resultPtr + } + + device := core.NewDevice(int(deviceType), privateKey, nil) + + handle := uintptr(unsafe.Pointer(device)) + devices[privateKeyBase64] = device + handles[handle] = device + resultPtr.handle = C.size_t(handle) + return resultPtr +} + +// 关闭nhp_device +// 输入: +// handle: NHP device句柄 +// +//export nhp_device_close +func nhp_device_close(handle uintptr) { + device, found := handles[handle] + if found { + delete(handles, handle) + for k, v := range devices { + if v == device { + delete(devices, k) + return + } + } + } +} + +// 将载荷数据(明文消息)进行NHP噪声加密并生成NHP加密报文 +// 输入: +// handle: NHP device句柄 +// msgType: NHP消息类型 +// peerPbk: 对端peer公钥 +// peerPbkLen: 对端peer公钥长度 +// data: 明文载荷 +// dataLen: 明文载荷长度 +// params: 加密参数,见NhpEncryptParams结构体 +// 返回: +// NhpEncryptResult指针,见NhpEncryptResult结构体 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpEncryptResult函数 +// +//export nhp_device_encrypt_data +func nhp_device_encrypt_data(handle uintptr, msgType C.int, peerPbk *C.uchar, peerPbkLen C.int, data *C.uchar, dataLen C.int, params C.NhpEncryptParams) *C.NhpEncryptResult { + resultPtr := (*C.NhpEncryptResult)(C.malloc(C.sizeof_NhpEncryptResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpEncryptResult) + + device, found := handles[handle] + if !found { + resultPtr.errCode = C.ERR_NHP_DEVICE_NOT_INITIALIZED + resultPtr.errMsg = C.CString("nhp device not initialized") + return resultPtr + } + + md := &core.MsgData{ + HeaderType: int(msgType), + CipherScheme: int(params.cipherScheme), + PeerPk: C.GoBytes(unsafe.Pointer(peerPbk), peerPbkLen), + Message: C.GoBytes(unsafe.Pointer(data), dataLen), + Compress: params.compress != 0, + TransactionId: uint64(params.assignTransactionId), + ExternalCookie: (*[core.CookieSize]byte)(unsafe.Pointer(¶ms.cookie)), + } + + mad, err := device.MsgToPacket(md) + if err != nil { + nhpError := err.(*core.Error) + if nhpError != nil { + resultPtr.errCode = C.int(nhpError.ErrorNumber()) + } else { + resultPtr.errCode = -1 + } + resultPtr.errMsg = C.CString(err.Error()) + } else { + resultPtr.transactionId = C.ulonglong(mad.TransactionId) + resultPtr.packet = (*C.uchar)(C.CBytes(mad.BasePacket.Content)) + resultPtr.packetLen = C.int(len(mad.BasePacket.Content)) + } + + return resultPtr +} + +// 将载荷数据(明文消息)进行NHP噪声加密并生成NHP报文 +// 输入: +// handle: NHP device句柄 +// packet: 待解析的NHP加密报文 +// packetLen: NHP加密报文长度 +// 返回: +// NhpDecryptResult指针,见NhpDecryptResult结构体 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpDecryptResult函数 +// +//export nhp_device_decrypt_packet +func nhp_device_decrypt_packet(handle uintptr, packet *C.uchar, packetLen C.int, context C.NhpConnContext) *C.NhpDecryptResult { + resultPtr := (*C.NhpDecryptResult)(C.malloc(C.sizeof_NhpDecryptResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpDecryptResult) + + device, found := handles[handle] + if !found { + resultPtr.errCode = C.ERR_NHP_DEVICE_NOT_INITIALIZED + resultPtr.errMsg = C.CString("nhp device not initialized") + return resultPtr + } + + var cookieStore *core.CookieStore + if context.cookieStore != nil { + cookieStore = (*core.CookieStore)(unsafe.Pointer(context.cookieStore)) + } + + var lastPeerSendTime *int64 + if context.lastPeerSendTime != nil { + lastPeerSendTime = (*int64)(unsafe.Pointer(context.lastPeerSendTime)) + } + + var peerPbk *[core.PublicKeySizeEx]byte + if context.peerPbk != nil { + peerPbk = (*[core.PublicKeySizeEx]byte)(unsafe.Pointer(context.peerPbk)) + } + + pd := &core.PacketData{ + BasePacket: &core.Packet{Content: C.GoBytes(unsafe.Pointer(packet), packetLen)}, + ConnLastRemoteSendTime: lastPeerSendTime, + ConnCookieStore: cookieStore, + ConnPeerPublicKey: peerPbk, + } + + ppd, err := device.PacketToMsg(pd) + + if err != nil { + nhpError := err.(*core.Error) + if nhpError != nil { + resultPtr.errCode = C.int(nhpError.ErrorNumber()) + } else { + resultPtr.errCode = -1 + } + resultPtr.errMsg = C.CString(err.Error()) + } else { + resultPtr.msgType = C.int(ppd.HeaderType) + if ppd.HeaderType != core.NHP_KPL { + resultPtr.msgTransactionId = C.ulonglong(ppd.SenderTrxId) + resultPtr.msgId = (*C.uchar)(C.CBytes(ppd.SenderIdentity)) + resultPtr.msgIdLen = C.int(len(ppd.SenderIdentity)) + resultPtr.data = (*C.uchar)(C.CBytes(ppd.BodyMessage)) + resultPtr.dataLen = C.int(len(ppd.BodyMessage)) + } + } + + return resultPtr +} + +// 设置nhp device的过载模式 +// 输入: +// handle: NHP device句柄 +// overload: 是否开启过载模式 +// 返回: +// NhpResult指针,见NhpResult结构体 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpResult函数 +// +//export nhp_device_set_overload +func nhp_device_set_overload(handle uintptr, overload bool) *C.NhpResult { + resultPtr := (*C.NhpResult)(C.malloc(C.sizeof_NhpResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpResult) + + device, found := handles[handle] + if !found { + resultPtr.errCode = C.ERR_NHP_DEVICE_NOT_INITIALIZED + resultPtr.errMsg = C.CString("nhp device not initialized") + return resultPtr + } + + device.SetOverload(overload) + return resultPtr +} + +// 进行SM4 AEAD加密 +// 输入: +// key: 密钥缓冲 +// keyLen: 密钥长度(取前16字节) +// nonce: 计数器计数值缓冲 +// nonceLen: 计数器计数值长度(须12字节) +// plain: 明文数据 +// plainLen: 明文长度 +// addtionalData: 附带验证数据 +// addtionalDataLen: 附带验证数据长度 +// 返回: +// NhpEncryptResult指针,密文由packet与packetLen表示 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpEncryptResult函数 +// +//export nhp_sm4_aead_encrypt +func nhp_sm4_aead_encrypt(key *C.uchar, keyLen C.int, nonce *C.uchar, nonceLen C.int, plain *C.uchar, plainLen C.int, additionalData *C.uchar, additionalDataLen C.int) *C.NhpEncryptResult { + resultPtr := (*C.NhpEncryptResult)(C.malloc(C.sizeof_NhpEncryptResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpEncryptResult) + + var aeadKey [core.SymmetricKeySize]byte + buf := make([]byte, plainLen+16) + copy(aeadKey[:], C.GoBytes(unsafe.Pointer(key), keyLen)) + + aead := core.AeadFromKey(core.GCM_SM4, &aeadKey) + cipher := aead.Seal(buf[:0], C.GoBytes(unsafe.Pointer(nonce), nonceLen), C.GoBytes(unsafe.Pointer(plain), plainLen), C.GoBytes(unsafe.Pointer(additionalData), additionalDataLen)) + if cipher == nil { + resultPtr.errCode = 1 + resultPtr.errMsg = C.CString("GCM encryption failed") + return resultPtr + } + + resultPtr.packet = (*C.uchar)(C.CBytes(cipher)) + resultPtr.packetLen = C.int(len(cipher)) + return resultPtr +} + +// 进行SM4 AEAD解密 +// 输入: +// key: 密钥缓冲 +// keyLen: 密钥长度(取前16字节) +// nonce: 计数器计数值缓冲(须与加密时计数值相同) +// nonceLen: 计数器计数值长度(须12字节) +// cipher: 密文数据 +// cipherLen: 密文长度 +// addtionalData: 附带验证数据 +// addtionalDataLen: 附带验证数据长度 +// 返回: +// NhpDecryptResult指针,明文由data与dataLen表示 +// 调用者:调用完成后释放返回数据,见nhp_free_NhpEncryptResult函数 +// +//export nhp_sm4_aead_decrypt +func nhp_sm4_aead_decrypt(key *C.uchar, keyLen C.int, nonce *C.uchar, nonceLen C.int, cipher *C.uchar, cipherLen C.int, additionalData *C.uchar, additionalDataLen C.int) *C.NhpDecryptResult { + resultPtr := (*C.NhpDecryptResult)(C.malloc(C.sizeof_NhpDecryptResult)) + C.memset(unsafe.Pointer(resultPtr), 0, C.sizeof_NhpDecryptResult) + + var aeadKey [core.SymmetricKeySize]byte + buf := make([]byte, cipherLen) + copy(aeadKey[:], C.GoBytes(unsafe.Pointer(key), keyLen)) + + aead := core.AeadFromKey(core.GCM_SM4, &aeadKey) + plain, err := aead.Open(buf[:0], C.GoBytes(unsafe.Pointer(nonce), nonceLen), C.GoBytes(unsafe.Pointer(cipher), cipherLen), C.GoBytes(unsafe.Pointer(additionalData), additionalDataLen)) + if err != nil { + resultPtr.errCode = 1 + resultPtr.errMsg = C.CString(fmt.Sprintf("GCM decryption failed: %s", err)) + return resultPtr + } + + resultPtr.data = (*C.uchar)(C.CBytes(plain)) + resultPtr.dataLen = C.int(len(plain)) + return resultPtr +} diff --git a/core/main/nhpdevicedef.h b/core/main/nhpdevicedef.h new file mode 100644 index 00000000..46122216 --- /dev/null +++ b/core/main/nhpdevicedef.h @@ -0,0 +1,137 @@ +#ifdef __cplusplus +extern "C" { +#endif +#ifndef NHPDEVICEDEF_H +#define NHPDEVICEDEF_H + +#include +#include +#include + +#define NHP_COOKIE_SIZE 32 +#define NHP_PUBLIC_KEY_SIZE 64 + +typedef enum _NhpDeviceType { + NHP_AGENT = 1, + NHP_SERVER, + NHP_AC, +} NhpDeviceType; + +typedef enum _NhpCipherScheme { + NHP_CIPHER_SCHEME_CURVE, + NHP_CIPHER_SCHEME_GMSM, +} NhpCipherScheme; + +typedef enum _NhpMsgType { + NHP_KPL = 0, // general keepalive packet + NHP_KNK, // agent sends knock to server + NHP_ACK, // server replies knock status to agent + NHP_AOP, // server asks ac for operation + NHP_ART, // ac replies server for operation result + NHP_LST, // agent requests server for listing services and applications + NHP_LRT, // server replies to agent with services and applications result + NHP_COK, // server sends cookie to agent + NHP_RKN, // agent sends reknock to server + NHP_RLY, // relay sends relayed packet to server + NHP_AOL, // ac sends online status to server + NHP_AAK, // server sends ack to ac after receving ac's online status + NHP_OTP, // agent requests server for one-time-password + NHP_REG, // agent asks server for registering + NHP_RAK, // server sends back ack when agent registers correctly + NHP_ACC, // agent sends to ac/resource for actual ip access + NHP_EXT, // agent requests immediate disconnection +} NhpMsgType; + +typedef struct _NhpResult { + size_t handle; // 初始化后返回的nhp device句柄 + int errCode; // 错误代码:无错误则为0,其它非0值表示错误 + char *errMsg; // 错误描述:为空则无错误,有值表示错误描述语句 +} NhpResult; + +typedef struct _NhpEncryptParams { + unsigned char cipherScheme; // 指定消息采用的加密方案 0: curve25519/chacha20poly1305/blake2s, 1: sm2/sm4/sm3 + unsigned char compress; // true: 使用zlib压缩明文消息 + unsigned char reserved0; + unsigned char reserved1; + unsigned long long assignTransactionId; // 如果要响应之前接收的NHP包,则需要指定使用发送方上次的流水号, 值为0则不指定,由本地生成新的流水号 + unsigned char cookie[NHP_COOKIE_SIZE]; // 对端peer要求重新敲门所指定的cookie值,注:device在每个peer连接下具有不同的cookie +} NhpEncryptParams; + +typedef struct _NhpEncryptResult { + int errCode; // 错误代码 + int packetLen; // 报文长度 + unsigned long long transactionId; // 本地交易流水号 + char *errMsg; // 错误描述 + unsigned char *packet; // 报文数据 +} NhpEncryptResult; + +typedef struct _NhpPubicKey { + unsigned char data[NHP_PUBLIC_KEY_SIZE]; +} NhpPubicKey; + +typedef struct _NhpCookieStore { + unsigned char currCookie[NHP_COOKIE_SIZE]; + unsigned char prevCookie[NHP_COOKIE_SIZE]; + long long lastCookieTime; +} NhpCookieStore; + +typedef struct _NhpConnContext { + NhpPubicKey *peerPbk; + NhpCookieStore *cookieStore; + long long *lastPeerSendTime; +} NhpConnContext; + +typedef struct _NhpDecryptResult { + int errCode; // 错误代码 + int msgType; // 消息类型 + int msgIdLen; // 发送方标识长度 + int dataLen; // 载荷长度 + unsigned long long msgTransactionId; // 消息发送方交易流水号 + char *errMsg; // 错误描述 + unsigned char *msgId; // 消息发送方标识 + unsigned char *data; // 载荷数据 +} NhpDecryptResult; + +typedef enum _NhpError { + // general + ERR_NHP_SUCCESS = 0, + ERR_NHP_DEVICE_NOT_INITIALIZED = 30000, + ERR_NHP_DEVICE_ALREADY_CREATED, + ERR_NHP_CIPHER_NOT_SUPPORTED, + ERR_NHP_OPERATION_NOT_APPLICABLE, + ERR_NHP_CREATE_DEVICE_FAILED, + ERR_NHP_CLOSE_DEVICE_FAILED, + ERR_NHP_SDK_RUNTIME_PANIC, + + // encryption + ERR_NHP_EMPTY_PEER_PUBLIC_KEY = 31001, + ERR_NHP_EPHERMAL_ECDH_PEER_FAILED, + ERR_NHP_DEVICE_ECDH_PEER_FAILED, + ERR_NHP_IDENTITY_TOO_LONG, + ERR_NHP_DATA_COMPRESSION_FAILED, + ERR_NHP_PACKET_SIZE_EXCEEDS_BUFFER, + + // decryption + ERR_NHP_CLOSE_CONNECTION = 32001, + ERR_NHP_INCORRECT_PACKET_SIZE, + ERR_NHP_MESSAGE_TYPE_NOT_MATCH_DEVICE, + ERR_NHP_SERVER_OVERLOAD, + ERR_NHP_HMAC_CHECK_FAILED, + ERR_NHP_SERVER_HMAC_CHECK_FAILED, + ERR_NHP_DEVICE_ECDH_EPHERMAL_FAILED, + ERR_NHP_PEER_IDENTITY_VERIFICATION_FAILED, + ERR_NHP_AEAD_DECRYPTION_FAILED, + ERR_NHP_DATA_DECOMPRESSION_FAILED, + ERR_NHP_DEVICE_ECDH_OBTAINED_PEER_FAILED, + ERR_NHP_SERVER_REJECT_WITH_COOKIE, + ERR_NHP_REPLAY_PACKET_RECEIVED, + ERR_NHP_FLOOD_PACKET_RECEIVED, + ERR_NHP_STALE_PACKET_RECEIVED, + +} NhpError; + + +#endif // NHPDEVICEDEF_H +#ifdef __cplusplus +} +#endif diff --git a/core/packet.go b/core/packet.go new file mode 100644 index 00000000..d06a04d0 --- /dev/null +++ b/core/packet.go @@ -0,0 +1,224 @@ +package core + +import ( + "encoding/binary" + "fmt" + + "github.com/OpenNHP/opennhp/log" + "github.com/OpenNHP/opennhp/utils" +) + +const ( + NHP_KPL = iota // general keepalive packet + NHP_KNK // agent sends knock to server + NHP_ACK // server replies knock status to agent + NHP_AOP // server asks ac for operation + NHP_ART // ac replies server for operation result + NHP_LST // agent requests server for listing services and applications + NHP_LRT // server replies to agent with services and applications result + NHP_COK // server sends cookie to agent + NHP_RKN // agent sends reknock to server + NHP_RLY // relay sends relayed packet to server + NHP_AOL // ac sends online status to server + NHP_AAK // server sends ack to ac after receving ac's online status + NHP_OTP // agent requests server for one-time-password + NHP_REG // agent asks server for registering + NHP_RAK // server sends back ack when agent registers correctly + NHP_ACC // agent sends to ac/resource for actual ip access + NHP_EXT // agent requests immediate disconnection +) + +var nhpHeaderTypeStrings []string = []string{ + "NHP-KPL", // general keepalive packet + "NHP-KNK", // agent sends knock to server + "NHP-ACK", // server replies knock status to agent + "NHP-AOP", // server asks ac for operation + "NHP-ART", // ac replies server for operation result + "NHP-LST", // agent requests server for listing services and applications + "NHP-LRT", // server replies to agent with services and applications result + "NHP-COK", // server sends cookie to agent + "NHP-RKN", // agent sends reknock to server + "NHP-RLY", // relay sends relayed packet to server + "NHP-AOL", // ac sends online status to server + "NHP-AAK", // server sends ack to ac after receving ac's online status + "NHP-OTP", // agent requests server for one-time-password + "NHP-REG", // agent asks server for registering + "NHP-RAK", // server sends back ack when agent registers correctly + "NHP-ACC", // agent sends to ac/resource for actual ip access + "NHP-EXT", // agent requests immediate disconnection +} + +func HeaderTypeToString(t int) string { + if t < len(nhpHeaderTypeStrings) { + return nhpHeaderTypeStrings[t] + } + return "UNKNOWN" +} + +func HeaderTypeToDeviceType(t int) int { + switch t { + case NHP_KNK, NHP_LST, NHP_RKN, NHP_OTP, NHP_REG, NHP_ACC, NHP_EXT: + return NHP_AGENT + + case NHP_ACK, NHP_AOP, NHP_LRT, NHP_COK, NHP_AAK, NHP_RAK: + return NHP_SERVER + + case NHP_AOL, NHP_ART: + return NHP_AC + + case NHP_RLY: + return NHP_RELAY + } + + return NHP_NO_DEVICE +} + +type PacketBuffer = [PacketBufferSize]byte + +// packet buffer pool +type PacketBufferPool struct { + pool *utils.WaitPool +} + +func (bp *PacketBufferPool) Init(max uint32) { + bp.pool = utils.NewWaitPool(max, func() any { return new(PacketBuffer) }) +} + +// must be called after Init() +func (bp *PacketBufferPool) Get() *PacketBuffer { + return bp.pool.Get().(*PacketBuffer) +} + +// must be called after Init() +func (bp *PacketBufferPool) Put(packet *PacketBuffer) { + bp.pool.Put(packet) +} + +type Packet struct { + Buf *PacketBuffer + HeaderType int + PoolAllocated bool + KeepAfterSend bool // only applicable for sending + Content []byte +} + +// header flags (bit 0 - bit 11) +const ( + NHP_FLAG_EXTENDEDLENGTH = 1 << iota + NHP_FLAG_COMPRESS +) + +// cipher scheme combination (bit 11 - bit 15) +const ( + NHP_FLAG_SCHEME_GMSM = 0 << 12 +) + +type Header interface { + SetTypeAndPayloadSize(int, int) + TypeAndPayloadSize() (int, int) + Size() int + SetVersion(int, int) + Version() (int, int) + SetFlag(uint16) + Flag() uint16 + SetCounter(uint64) + Counter() uint64 + Bytes() []byte + NonceBytes() []byte + EphermeralBytes() []byte + StaticBytes() []byte + TimestampBytes() []byte + IdentityBytes() []byte + HMACBytes() []byte +} + +func (pkt *Packet) Flag() uint16 { + return binary.BigEndian.Uint16(pkt.Content[10:12]) +} + +func (pkt *Packet) HeaderTypeAndSize() (t int, s int) { + preamble := binary.BigEndian.Uint32(pkt.Content[0:4]) + tns := preamble ^ binary.BigEndian.Uint32(pkt.Content[4:8]) + t = int((tns & 0xFFFF0000) >> 16) + s = int(tns & 0x0000FFFF) + pkt.HeaderType = t + + return t, s +} + +func (pkt *Packet) Counter() uint64 { + return binary.BigEndian.Uint64(pkt.Content[16:24]) +} + +func (d *Device) CheckRecvHeaderType(t int) bool { + // NHP_KPL is handled elsewhere + switch d.deviceType { + case NHP_AGENT: + switch t { + case NHP_ACK, NHP_LRT, NHP_COK, NHP_RAK: + return true + } + case NHP_SERVER: + switch t { + case NHP_REG, NHP_KNK, NHP_LST, NHP_RKN, NHP_EXT, NHP_ART, NHP_RLY, NHP_AOL, NHP_OTP: + return true + } + case NHP_AC: + switch t { + case NHP_AOP, NHP_LRT, NHP_AAK: + return true + } + case NHP_RELAY: + switch t { + case NHP_REG, NHP_KNK, NHP_ACK, NHP_LST, NHP_LRT, NHP_COK, NHP_RKN, NHP_EXT: + return true + } + } + + log.Info("Device type: %d, recv header type %d not allowed", d.deviceType, t) + return false +} + +func (d *Device) RecvPrecheck(pkt *Packet) (int, int, error) { + var headerSize int + flag := pkt.Flag() + if flag&NHP_FLAG_EXTENDEDLENGTH == 0 { + headerSize = HeaderSize + } else { + headerSize = HeaderSizeEx + } + + // check type and payload size + t, s := pkt.HeaderTypeAndSize() + if t == NHP_KPL { + if s == 0 { + return t, s, nil + } else { + return t, s, fmt.Errorf("keepalive packet size is incorrect") + } + } + + if !d.CheckRecvHeaderType(t) { + return t, s, fmt.Errorf("packet header type does not match device") + } + + totalLen := len(pkt.Content) + if totalLen != headerSize+s { + return t, s, fmt.Errorf("packet total size is incorrect") + } + + return t, s, nil +} + +func (d *Device) AllocatePoolPacket() *Packet { + buf := d.pool.Get() + return &Packet{Buf: buf, Content: buf[:], PoolAllocated: true} +} + +func (d *Device) ReleasePoolPacket(pkt *Packet) { + if pkt != nil && pkt.Buf != nil && pkt.PoolAllocated { + d.pool.Put(pkt.Buf) + pkt.Buf = nil + pkt.Content = nil + } +} diff --git a/nhp/peer.go b/core/peer.go similarity index 99% rename from nhp/peer.go rename to core/peer.go index 2f735fa8..2b9ad3ea 100644 --- a/nhp/peer.go +++ b/core/peer.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "encoding/base64" diff --git a/nhp/readme.md b/core/readme.md similarity index 85% rename from nhp/readme.md rename to core/readme.md index 5570212e..82e1a78d 100644 --- a/nhp/readme.md +++ b/core/readme.md @@ -2,7 +2,7 @@ 1. Device负责NHP报文与消息的转换。Device初始化时需要指定类型和私钥。Device视自身类型只对相应的包进行处理。 -2. 用于承载发送和接收报文的buffer比较大,所以由Device的内存Pool统一发放并回收(如果依赖于Go后台垃圾回收,高并发时会造成大量内存开销)。所以在开发时一定要注意buffer的分配**Device.AllocateUdpPacket\(\)** 和回收**Device.ReleaseUdpPacket\(\)**。 +2. 用于承载发送和接收报文的buffer比较大,所以由Device的内存Pool统一发放并回收(如果依赖于Go后台垃圾回收,高并发时会造成大量内存开销)。所以在开发时一定要注意buffer的分配**Device.AllocatePoolPacket\(\)** 和回收**Device.ReleasePoolPacket\(\)**。 - 报文buffer回收点位于 - 发送报文被发送后(本地transaction除外) @@ -21,7 +21,7 @@ 7. 在建立发送请求时,需要创建**MsgAssembler**结构体。 - - Agent和Door必须填写消息类型**HeaderType**、对端**RemoteAddr**、对端公钥**PeerPk**和消息明文**Message**(如无特殊情况都采用消息压缩)。将填写好的**MsgAssembler**发给各自的**sendMessageRoutine\(\)** 即可进行新连接的建立或寻找已存在连接并进行转换后报文的发送。 + - Agent和AC必须填写消息类型**HeaderType**、对端**RemoteAddr**、对端公钥**PeerPk**和消息明文**Message**(如无特殊情况都采用消息压缩)。将填写好的**MsgAssembler**发给各自的**sendMessageRoutine\(\)** 即可进行新连接的建立或寻找已存在连接并进行转换后报文的发送。 - Server必须填写消息类型**HeaderType**、连接上下文**ConnData**、对端公钥**PeerPk**和消息明文**Message**(如无特殊情况都采用消息压缩)。将填写好的**MsgAssembler**发给**Device.SendMsgToPacket\(\)** 即可进行转换后报文的发送。 diff --git a/nhp/responder.go b/core/responder.go similarity index 65% rename from nhp/responder.go rename to core/responder.go index 53827126..ba6972c9 100644 --- a/nhp/responder.go +++ b/core/responder.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "bytes" @@ -15,39 +15,51 @@ import ( "unsafe" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core/scheme/curve" + "github.com/OpenNHP/opennhp/core/scheme/gmsm" "github.com/OpenNHP/opennhp/log" ) +type ResponderScheme interface { + CreatePacketParserData(d *Device, pd *PacketData) (ppd *PacketParserData, err error) + DerivePacketParserDataFromPrevAssemblerData(mad *MsgAssemblerData, pkt *Packet, initTime int64) (ppd *PacketParserData) + validatePeer(d *Device, ppd *PacketParserData) (err error) + decryptBody(d *Device, ppd *PacketParserData) (err error) +} + type CookieStore struct { - Cookie [CookieSize]byte + CurrCookie [CookieSize]byte PrevCookie [CookieSize]byte LastCookieTime int64 } -func (cs *CookieStore) Set() { - SetZero(cs.Cookie[:]) - SetZero(cs.PrevCookie[:]) +func (cs *CookieStore) Set(cookie []byte) { + copy(cs.PrevCookie[:], cs.CurrCookie[:]) + copy(cs.CurrCookie[:], cookie) } func (cs *CookieStore) Clear() { - SetZero(cs.Cookie[:]) + SetZero(cs.CurrCookie[:]) SetZero(cs.PrevCookie[:]) } type PacketData struct { - BasePacket *UdpPacket - ConnData *ConnectionData - PrevAssemblerData *MsgAssemblerData - InitTime int64 - HeaderType int - DecryptedMsgCh chan *PacketParserData + BasePacket *Packet + ConnData *ConnectionData + PrevAssemblerData *MsgAssemblerData + ConnLastRemoteSendTime *int64 + ConnCookieStore *CookieStore + ConnPeerPublicKey *[PublicKeySizeEx]byte + InitTime int64 + DecryptedMsgCh chan *PacketParserData } type PacketParserData struct { - device *Device - basePacket *UdpPacket - ConnData *ConnectionData - Ciphers *CipherSuite + device *Device + basePacket *Packet + ConnData *ConnectionData + CipherScheme int + Ciphers *CipherSuite deviceEcdh Ecdh header Header @@ -57,7 +69,7 @@ type PacketParserData struct { chainKey [SymmetricKeySize]byte LocalInitTime int64 - SenderId uint64 + SenderTrxId uint64 noise NoiseFactory // int HeaderType int @@ -66,8 +78,13 @@ type PacketParserData struct { BodyCompress bool Overload bool - RemotePubKey []byte - BodyMessage []byte + SenderIdentity []byte + SenderMidPublicKey []byte + ConnLastRemoteSendTime *int64 + ConnCookieStore *CookieStore + ConnPeerPublicKey *[PublicKeySizeEx]byte + RemotePubKey []byte + BodyMessage []byte decryptedMsgCh chan<- *PacketParserData feedbackMsgCh chan<- *PacketParserData @@ -82,19 +99,30 @@ func (d *Device) createPacketParserData(pd *PacketData) (ppd *PacketParserData, ppd.device = d ppd.basePacket = pd.BasePacket ppd.ConnData = pd.ConnData + ppd.ConnCookieStore = pd.ConnCookieStore ppd.LocalInitTime = pd.InitTime + ppd.ConnLastRemoteSendTime = pd.ConnLastRemoteSendTime + ppd.ConnPeerPublicKey = pd.ConnPeerPublicKey ppd.decryptedMsgCh = pd.DecryptedMsgCh // init header and init device ecdh - ppd.HeaderFlag = binary.BigEndian.Uint16(ppd.basePacket.Packet[10:12]) + ppd.HeaderFlag = binary.BigEndian.Uint16(ppd.basePacket.Content[10:12]) if ppd.HeaderFlag&NHP_FLAG_EXTENDEDLENGTH == 0 { - ppd.header = (*NHPHeader)(unsafe.Pointer(&ppd.basePacket.Packet[0])) - ppd.Ciphers = NewCipherSuite(false) - ppd.deviceEcdh = d.staticEcdh + ppd.CipherScheme = CIPHER_SCHEME_CURVE + ppd.header = (*curve.HeaderCurve)(unsafe.Pointer(&ppd.basePacket.Content[0])) + ppd.Ciphers = NewCipherSuite(CIPHER_SCHEME_CURVE) + ppd.deviceEcdh = d.staticEcdhCurve } else { - ppd.header = (*NHPHeaderEx)(unsafe.Pointer(&ppd.basePacket.Packet[0])) - ppd.Ciphers = NewCipherSuite(true) - ppd.deviceEcdh = d.staticEcdhEx + // check cipher scheme + switch ppd.HeaderFlag & (0xF << 12) { + case NHP_FLAG_SCHEME_GMSM: + fallthrough + default: + ppd.CipherScheme = CIPHER_SCHEME_GMSM + ppd.header = (*gmsm.HeaderGmsm)(unsafe.Pointer(&ppd.basePacket.Content[0])) + ppd.Ciphers = NewCipherSuite(CIPHER_SCHEME_GMSM) + ppd.deviceEcdh = d.staticEcdhGmsm + } } // init chain hash -> ChainHash0 @@ -124,28 +152,29 @@ func (d *Device) createPacketParserData(pd *PacketData) (ppd *PacketParserData, ppd.Overload = true if !ppd.IsAllowedAtOverload() { log.Critical("discard packet type %d due to overload", ppd.HeaderType) - err = fmt.Errorf("server overloaded, packet rejected") + err = ErrServerOverload return } } + // for RKN, check HMAC with cookie. For remaining allowed key messages, check HMAC without cookie. sumCookie := overload && ppd.HeaderType == NHP_RKN if !ppd.checkHMAC(sumCookie) { log.Error("HMAC validation failed on server side. sumCookie: %v", sumCookie) - err = fmt.Errorf("server hmac validation failed") + err = ErrServerHMACCheckFailed return } } else { if !ppd.checkHMAC(false) { log.Error("HMAC validation failed.") - err = fmt.Errorf("hmac validation failed") + err = ErrHMACCheckFailed return } } // get sender id - ppd.SenderId = ppd.header.Counter() + ppd.SenderTrxId = ppd.header.Counter() // init body message ppd.BodyCompress = ppd.HeaderFlag&NHP_FLAG_COMPRESS != 0 @@ -159,27 +188,31 @@ func (ppd *PacketParserData) deriveMsgAssemblerData(t int, compress bool, messag mad.device = ppd.device mad.connData = ppd.ConnData mad.HeaderType = t + mad.ciphers = ppd.Ciphers + mad.CipherScheme = ppd.CipherScheme mad.RemotePubKey = ppd.RemotePubKey mad.BodyCompress = compress mad.bodyMessage = message // init packet buffer - mad.BasePacket = mad.device.AllocateUdpPacket() + mad.BasePacket = mad.device.AllocatePoolPacket() mad.BasePacket.HeaderType = t // create header and init device ecdh - mad.ciphers = ppd.Ciphers - if mad.ciphers.IsUseGm() { - mad.HeaderFlag |= NHP_FLAG_EXTENDEDLENGTH - mad.header = (*NHPHeaderEx)(unsafe.Pointer(&mad.BasePacket.Buf[0])) - mad.deviceEcdh = mad.device.staticEcdhEx - } else { - mad.header = (*NHPHeader)(unsafe.Pointer(&mad.BasePacket.Buf[0])) - mad.deviceEcdh = mad.device.staticEcdh + switch mad.CipherScheme { + case CIPHER_SCHEME_CURVE: + mad.header = (*curve.HeaderCurve)(unsafe.Pointer(&mad.BasePacket.Buf[0])) + mad.deviceEcdh = mad.device.staticEcdhCurve + case CIPHER_SCHEME_GMSM: + fallthrough + default: + mad.header = (*gmsm.HeaderGmsm)(unsafe.Pointer(&mad.BasePacket.Buf[0])) + mad.deviceEcdh = mad.device.staticEcdhGmsm + } // continue with the sender's counter - mad.header.SetCounter(ppd.SenderId) + mad.header.SetCounter(ppd.SenderTrxId) // init chain hash -> ChainHash0 mad.chainHash = NewHash(mad.ciphers.HashType) @@ -212,26 +245,35 @@ func (ppd *PacketParserData) validatePeer() (err error) { // get ephermeral shared key ess := ppd.deviceEcdh.SharedSecret(ppd.header.EphermeralBytes()) if ess == nil { - log.Error("ephermal ECDH failed with peer") - err = fmt.Errorf("ephermal ECDH failed with peer") + log.Error("device ECDH failed with ephermal") + err = ErrDeviceECDHEphermalFailed return err } // prepare key for aead var key [SymmetricKeySize]byte + var aead cipher.AEAD // generate gcm key and decrypt device pubkey ChainKey1 -> ChainKey2 (ChainKey5 -> ChainKey6) ppd.noise.KeyGen2(&ppd.chainKey, &key, ppd.chainKey[:], ess[:]) SetZero(ess[:]) + peerPk := make([]byte, PublicKeySizeEx) - aead := AeadFromKey(ppd.Ciphers.GcmType, &key) - _, err = aead.Open(peerPk[:0], ppd.header.NonceBytes(), ppd.header.StaticBytes(), ppd.chainHash.Sum(nil)) - if err != nil { - log.Error("failed to decrypt peer pubkey") - return err + switch ppd.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + aead = AeadFromKey(ppd.Ciphers.GcmType, &key) + _, err = aead.Open(peerPk[:0], ppd.header.NonceBytes(), ppd.header.StaticBytes(), ppd.chainHash.Sum(nil)) + if err != nil { + log.Error("failed to decrypt peer pubkey") + return err + } } - if ppd.HeaderFlag&NHP_FLAG_EXTENDEDLENGTH == 0 { + if ppd.CipherScheme == CIPHER_SCHEME_CURVE { peerPk = peerPk[:PublicKeySize] } @@ -241,11 +283,13 @@ func (ppd *PacketParserData) validatePeer() (err error) { // ac does not validate nor store agent public key. Related msgtype: NHP_ACC. var peer Peer var toValidate bool + var peerDeviceType int + ppd.device.optionMutex.Lock() option := ppd.device.option ppd.device.optionMutex.Unlock() - peerDeviceType := HeaderTypeToDeviceType(ppd.HeaderType) + peerDeviceType = HeaderTypeToDeviceType(ppd.HeaderType) switch peerDeviceType { case NHP_AGENT: toValidate = !option.DisableAgentPeerValidation @@ -258,7 +302,6 @@ func (ppd *PacketParserData) validatePeer() (err error) { case NHP_RELAY: toValidate = !option.DisableRelayPeerValidation - } if toValidate { @@ -284,6 +327,9 @@ func (ppd *PacketParserData) validatePeer() (err error) { } ppd.RemotePubKey = peerPk + if ppd.ConnPeerPublicKey != nil { + copy((*ppd.ConnPeerPublicKey)[:], peerPk) + } // evolve chainhash ChainHash1 -> ChainHash2 ppd.chainHash.Write(ppd.header.StaticBytes()) @@ -291,23 +337,32 @@ func (ppd *PacketParserData) validatePeer() (err error) { // init shared key ss := ppd.deviceEcdh.SharedSecret(peerPk) if ss == nil { - log.Error("device ECDH failed with peer") - err = fmt.Errorf("device ECDH failed with peer") + log.Error("device ECDH failed with obtained peer") + err = ErrDeviceECDHObtainedPeerFailed return err } // generate gcm key and decrypt timestamp ChainKey2 -> ChainKey3 (ChainKey6 -> ChainKey7) ppd.noise.KeyGen2(&ppd.chainKey, &key, ppd.chainKey[:], ss[:]) SetZero(ss[:]) + var tsBytes [TimestampSize]byte - aead = AeadFromKey(ppd.Ciphers.GcmType, &key) - _, err = aead.Open(tsBytes[:0], ppd.header.NonceBytes(), ppd.header.TimestampBytes(), ppd.chainHash.Sum(nil)) - if err != nil { - log.Error("failed to decrypt timestamp") - return err + switch ppd.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + aead = AeadFromKey(ppd.Ciphers.GcmType, &key) + _, err = aead.Open(tsBytes[:0], ppd.header.NonceBytes(), ppd.header.TimestampBytes(), ppd.chainHash.Sum(nil)) + if err != nil { + log.Error("failed to decrypt timestamp") + return err + } } remoteSendTime := int64(binary.BigEndian.Uint64(tsBytes[:])) + if shouldCheckRecvAttack(ppd.device.deviceType, peerDeviceType, ppd.HeaderType) { // block remote if threat level is reached if remoteSendTime < ppd.ConnData.LastRemoteSendTime { @@ -362,9 +417,17 @@ func (ppd *PacketParserData) validatePeer() (err error) { // handle knock packet at overload before going into body decryption if ppd.device.deviceType == NHP_SERVER && ppd.Overload && ppd.HeaderType == NHP_KNK { - ppd.generateCookie() - ppd.sendCookie() - err = fmt.Errorf("server overloaded, sending back cookie") + switch ppd.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + ppd.generateCookie() + ppd.sendCookie() + err = ErrServerRejectWithCookie + } + return err } @@ -380,19 +443,23 @@ func (ppd *PacketParserData) validatePeer() (err error) { func (ppd *PacketParserData) decryptBody() (err error) { defer func() { + // clear secrets ppd.chainHash.Reset() ppd.chainHash = nil + SetZero(ppd.chainKey[:]) }() // message body is empty, skip decryption - if len(ppd.basePacket.Packet) == ppd.header.Size() { + if len(ppd.basePacket.Content) == ppd.header.Size() { return nil } - // decrypt body and reuse ppd.BasePacket.Buf space - body, err := ppd.bodyAead.Open(ppd.basePacket.Buf[ppd.header.Size():ppd.header.Size()], ppd.header.NonceBytes(), ppd.basePacket.Packet[ppd.header.Size():], ppd.chainHash.Sum(nil)) + // decrypt body and reuse ppd.BasePacket.Content space + body, err := ppd.bodyAead.Open(ppd.basePacket.Content[ppd.header.Size():ppd.header.Size()], ppd.header.NonceBytes(), ppd.basePacket.Content[ppd.header.Size():], ppd.chainHash.Sum(nil)) if err != nil { log.Critical("decrypt body failed: %v", err) + ErrAEADDecryptionFailed.SetExtraError(err) + err = ErrAEADDecryptionFailed return err } @@ -407,6 +474,8 @@ func (ppd *PacketParserData) decryptBody() (err error) { _, err = io.Copy(&buf, r) if err != nil { log.Critical("message decompression failed: %v", err) + ErrDataDecompressionFailed.SetExtraError(err) + err = ErrDataDecompressionFailed return err } @@ -418,6 +487,22 @@ func (ppd *PacketParserData) decryptBody() (err error) { return nil } +func (ppd *PacketParserData) makeCookieStore(cookieStore *CookieStore) *CookieStore { + if cookieStore != nil { + var tsBytes [TimestampSize]byte + currTime := time.Now().UnixNano() + if (currTime - cookieStore.LastCookieTime) > CookieRegenerateTime*int64(time.Second) { + copy(cookieStore.PrevCookie[:], cookieStore.CurrCookie[:]) + binary.BigEndian.PutUint64(tsBytes[:], uint64(currTime)) + ppd.noise.KeyGen1(&cookieStore.CurrCookie, ppd.header.EphermeralBytes(), tsBytes[:]) + cookieStore.LastCookieTime = currTime + } + return cookieStore + } + + return nil +} + func (ppd *PacketParserData) generateCookie() { var tsBytes [TimestampSize]byte currTime := time.Now().UnixNano() @@ -426,17 +511,17 @@ func (ppd *PacketParserData) generateCookie() { defer ppd.ConnData.Unlock() if (currTime - ppd.ConnData.CookieStore.LastCookieTime) > CookieRegenerateTime*int64(time.Second) { - copy(ppd.ConnData.CookieStore.PrevCookie[:], ppd.ConnData.CookieStore.Cookie[:]) + copy(ppd.ConnData.CookieStore.PrevCookie[:], ppd.ConnData.CookieStore.CurrCookie[:]) binary.BigEndian.PutUint64(tsBytes[:], uint64(currTime)) - ppd.noise.KeyGen1(&ppd.ConnData.CookieStore.Cookie, ppd.header.EphermeralBytes(), tsBytes[:]) + ppd.noise.KeyGen1(&ppd.ConnData.CookieStore.CurrCookie, ppd.header.EphermeralBytes(), tsBytes[:]) ppd.ConnData.CookieStore.LastCookieTime = currTime } } func (ppd *PacketParserData) sendCookie() { - cokStr := base64.StdEncoding.EncodeToString(ppd.ConnData.CookieStore.Cookie[:]) + cokStr := base64.StdEncoding.EncodeToString(ppd.ConnData.CookieStore.CurrCookie[:]) cokMsg := &common.ServerCookieMsg{ - TransactionId: ppd.SenderId, + TransactionId: ppd.SenderTrxId, Cookie: cokStr, } cokBytes, _ := json.Marshal(cokMsg) @@ -464,19 +549,26 @@ func (ppd *PacketParserData) checkHMAC(sumCookie bool) bool { ppd.hmacHash.Write(ppd.header.Bytes()[0:len]) if sumCookie { - ppd.ConnData.Lock() - defer ppd.ConnData.Unlock() - - if ppd.LocalInitTime < ppd.ConnData.CookieStore.LastCookieTime+CookieRoundTripTimeMs*int64(time.Millisecond) { - // cookie has already or nearly been updated, use previous cookie - ppd.hmacHash.Write(ppd.ConnData.CookieStore.PrevCookie[:]) - prevCookieHmac := ppd.hmacHash.Sum(nil) - return bytes.Equal(prevCookieHmac, ppd.header.HMACBytes()) - } else { - // use current cookie - ppd.hmacHash.Write(ppd.ConnData.CookieStore.Cookie[:]) - cookieHmac := ppd.hmacHash.Sum(nil) - return bytes.Equal(cookieHmac, ppd.header.HMACBytes()) + switch ppd.CipherScheme { + case CIPHER_SCHEME_CURVE: + fallthrough + case CIPHER_SCHEME_GMSM: + fallthrough + default: + ppd.ConnData.Lock() + defer ppd.ConnData.Unlock() + + if ppd.LocalInitTime < ppd.ConnData.CookieStore.LastCookieTime+CookieRoundTripTimeMs*int64(time.Millisecond) { + // cookie has already or nearly been updated, use previous cookie + ppd.hmacHash.Write(ppd.ConnData.CookieStore.PrevCookie[:]) + prevCookieHmac := ppd.hmacHash.Sum(nil) + return bytes.Equal(prevCookieHmac, ppd.header.HMACBytes()) + } else { + // use current cookie + ppd.hmacHash.Write(ppd.ConnData.CookieStore.CurrCookie[:]) + cookieHmac := ppd.hmacHash.Sum(nil) + return bytes.Equal(cookieHmac, ppd.header.HMACBytes()) + } } } else { calculatedHmac := ppd.hmacHash.Sum(nil) @@ -485,7 +577,7 @@ func (ppd *PacketParserData) checkHMAC(sumCookie bool) bool { } func (ppd *PacketParserData) Destroy() { - ppd.device.ReleaseUdpPacket(ppd.basePacket) + ppd.device.ReleasePoolPacket(ppd.basePacket) if ppd.hmacHash != nil { ppd.hmacHash.Reset() ppd.hmacHash = nil @@ -494,7 +586,6 @@ func (ppd *PacketParserData) Destroy() { ppd.chainHash.Reset() ppd.chainHash = nil } - SetZero(ppd.chainKey[:]) } func (ppd *PacketParserData) IsAllowedAtOverload() bool { diff --git a/core/scheme/curve/curve.go b/core/scheme/curve/curve.go new file mode 100644 index 00000000..766e9b2b --- /dev/null +++ b/core/scheme/curve/curve.go @@ -0,0 +1,93 @@ +package curve + +import ( + "crypto/rand" + "encoding/base64" + "fmt" + + "golang.org/x/crypto/curve25519" +) + +const ( + PrivateKeySize = 32 + PublicKeySize = 32 +) + +type Curve25519ECDH struct { + PrivKey [PrivateKeySize]byte + PubKey [PublicKeySize]byte + PrivKeyBase64 string + PubKeyBase64 string + BriefName string +} + +func (c *Curve25519ECDH) SetPrivateKey(prk []byte) (err error) { + copy(c.PrivKey[:], prk[:PrivateKeySize]) + pbk, err := curve25519.X25519(c.PrivKey[:], curve25519.Basepoint) + if err != nil { + return err + } + copy(c.PubKey[:], pbk) + c.PrivKeyBase64 = base64.StdEncoding.EncodeToString(c.PrivKey[:]) + c.PubKeyBase64 = base64.StdEncoding.EncodeToString(c.PubKey[:]) + c.BriefName = fmt.Sprintf("%s...%s", c.PubKeyBase64[0:4], c.PubKeyBase64[39:43]) + + return nil +} + +func (c *Curve25519ECDH) PrivateKey() []byte { + return c.PrivKey[:] +} + +func (c *Curve25519ECDH) PrivateKeyBase64() string { + return c.PrivKeyBase64 +} + +func (c *Curve25519ECDH) PublicKey() []byte { + return c.PubKey[:] +} + +func (c *Curve25519ECDH) PublicKeyBase64() string { + return c.PubKeyBase64 +} + +func (c *Curve25519ECDH) SharedSecret(pbk []byte) []byte { + if len(pbk) != PublicKeySize { + return nil + } + + sk, err := curve25519.X25519(c.PrivKey[:], pbk) + if err != nil { + return nil + } + + // 32 bytes key + return sk[:] +} + +func (c *Curve25519ECDH) Name() string { + return c.BriefName +} + +func (c *Curve25519ECDH) Identity() []byte { + return nil +} + +func (c *Curve25519ECDH) MidPublicKey() []byte { + return nil +} + +func NewECDH() *Curve25519ECDH { + key := make([]byte, PrivateKeySize) + _, err := rand.Read(key) + if err != nil { + return nil + } + // clamp + key[0] &= 248 + key[31] = (key[31] & 127) | 64 + var c Curve25519ECDH + c.SetPrivateKey(key) + + return &c +} diff --git a/core/scheme/curve/header.go b/core/scheme/curve/header.go new file mode 100644 index 00000000..5ebf4241 --- /dev/null +++ b/core/scheme/curve/header.go @@ -0,0 +1,113 @@ +package curve + +import ( + "encoding/binary" + "unsafe" + + "github.com/OpenNHP/opennhp/utils" +) + +const ( + HeaderCommonSize = 24 + HashSize = 32 + GCMNonceSize = 12 + GCMTagSize = 16 + TimestampSize = 8 + HeaderSize = HeaderCommonSize + PublicKeySize + PublicKeySize + GCMTagSize + TimestampSize + GCMTagSize + HashSize +) + +type HeaderCurve struct { + HeaderCommon [HeaderCommonSize]byte + Ephermeral [PublicKeySize]byte + Static [PublicKeySize + GCMTagSize]byte + Timestamp [TimestampSize + GCMTagSize]byte + HMAC [HashSize]byte +} + +// header flags (bit 0 - bit 11) +const ( + NHP_FLAG_EXTENDEDLENGTH = 1 << iota + NHP_FLAG_COMPRESS +) + +// curve header implementations +func (h *HeaderCurve) TypeAndPayloadSize() (t int, s int) { + preamble := binary.BigEndian.Uint32(h.HeaderCommon[0:4]) + tns := preamble ^ binary.BigEndian.Uint32(h.HeaderCommon[4:8]) + t = int((tns & 0xFFFF0000) >> 16) + s = int(tns & 0x0000FFFF) + return t, s +} + +func (h *HeaderCurve) SetTypeAndPayloadSize(t int, s int) { + preamble := utils.GetRandomUint32() + t32 := uint32((t & 0x0000FFFF) << 16) + s32 := uint32(s & 0x0000FFFF) + tns := preamble ^ (s32 | t32) + binary.BigEndian.PutUint32(h.HeaderCommon[0:4], preamble) + binary.BigEndian.PutUint32(h.HeaderCommon[4:8], tns) +} + +func (h *HeaderCurve) Size() int { + return HeaderSize +} + +func (h *HeaderCurve) Version() (int, int) { + major := h.HeaderCommon[8] + minor := h.HeaderCommon[9] + return int(major), int(minor) +} + +func (h *HeaderCurve) SetVersion(major int, minor int) { + h.HeaderCommon[8] = uint8(major) + h.HeaderCommon[9] = uint8(minor) +} + +func (h *HeaderCurve) Flag() uint16 { + return binary.BigEndian.Uint16(h.HeaderCommon[10:12]) +} + +func (h *HeaderCurve) SetFlag(flag uint16) { + flag &= ^uint16(NHP_FLAG_EXTENDEDLENGTH) + flag &= 0xF << 12 + binary.BigEndian.PutUint16(h.HeaderCommon[10:12], flag) +} + +func (h *HeaderCurve) NonceBytes() []byte { + var nonce [GCMNonceSize]byte + copy(nonce[4:GCMNonceSize], h.HeaderCommon[16:24]) + return nonce[:] +} + +func (h *HeaderCurve) SetCounter(counter uint64) { + binary.BigEndian.PutUint64(h.HeaderCommon[16:24], counter) +} + +func (h *HeaderCurve) Counter() uint64 { + return binary.BigEndian.Uint64(h.HeaderCommon[16:24]) +} + +func (h *HeaderCurve) Bytes() []byte { + pHeader := (*[HeaderSize]byte)(unsafe.Pointer(&h.HeaderCommon)) + return pHeader[:] +} + +func (h *HeaderCurve) EphermeralBytes() []byte { + return h.Ephermeral[:] +} + +func (h *HeaderCurve) StaticBytes() []byte { + return h.Static[:] +} + +func (h *HeaderCurve) TimestampBytes() []byte { + return h.Timestamp[:] +} + +func (h *HeaderCurve) IdentityBytes() []byte { + return nil +} + +func (h *HeaderCurve) HMACBytes() []byte { + return h.HMAC[:] +} diff --git a/core/scheme/curve/responder.go b/core/scheme/curve/responder.go new file mode 100644 index 00000000..bca43037 --- /dev/null +++ b/core/scheme/curve/responder.go @@ -0,0 +1 @@ +package curve diff --git a/core/scheme/gmsm/gmsm.go b/core/scheme/gmsm/gmsm.go new file mode 100644 index 00000000..d694a04d --- /dev/null +++ b/core/scheme/gmsm/gmsm.go @@ -0,0 +1,229 @@ +package gmsm + +import ( + "crypto/ecdh" + "crypto/ecdsa" + "crypto/rand" + "encoding/base64" + "fmt" + "math/big" + + "github.com/emmansun/gmsm/sm2" +) + +const ( + PrivateKeySize = 32 + PublicKeySize = 64 +) + +type SM2ECDH struct { + PrivKey [PrivateKeySize]byte + PubKey [PublicKeySize]byte + prvK *ecdh.PrivateKey + PrivKeyBase64 string + PubKeyBase64 string + BriefName string +} + +func (s *SM2ECDH) SetPrivateKey(prk []byte) (err error) { + copy(s.PrivKey[:], prk[:PrivateKeySize]) + s.prvK, err = ecdh.P256().NewPrivateKey(prk) + if err != nil { + return err + } + copy(s.PubKey[:], s.prvK.PublicKey().Bytes()[1:1+PublicKeySize]) + s.PrivKeyBase64 = base64.StdEncoding.EncodeToString(s.PrivKey[:]) + s.PubKeyBase64 = base64.StdEncoding.EncodeToString(s.PubKey[:]) + s.BriefName = fmt.Sprintf("%s...%s", s.PubKeyBase64[0:4], s.PubKeyBase64[39:43]) + + return nil +} + +func (s *SM2ECDH) PrivateKey() []byte { + return s.PrivKey[:] +} + +func (s *SM2ECDH) PrivateKeyBase64() string { + return s.PrivKeyBase64 +} + +func (s *SM2ECDH) PublicKey() []byte { + return s.PubKey[:] +} + +func (s *SM2ECDH) PublicKeyBase64() string { + return s.PubKeyBase64 +} + +func (s *SM2ECDH) SharedSecret(pbk []byte) []byte { + if len(pbk) != PublicKeySize { + return nil + } + + var pkBytes [1 + PublicKeySize]byte + pkBytes[0] = 4 // uncompressed header + copy(pkBytes[1:1+PublicKeySize], pbk[:PublicKeySize]) + + pubK, err := ecdh.P256().NewPublicKey(pkBytes[:]) + if err != nil { + return nil + } + + sk, err := s.prvK.ECDH(pubK) + if err != nil { + return nil + } + + // 32 bytes key + return sk[:] +} + +func (s *SM2ECDH) Name() string { + return s.BriefName +} + +func (s *SM2ECDH) Identity() []byte { + return nil +} + +func (c *SM2ECDH) MidPublicKey() []byte { + return nil +} + +func NewECDH() *SM2ECDH { + var err error + var s SM2ECDH + s.prvK, err = ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return nil + } + copy(s.PrivKey[:], s.prvK.Bytes()) + copy(s.PubKey[:], s.prvK.PublicKey().Bytes()[1:1+PublicKeySize]) + s.PrivKeyBase64 = base64.StdEncoding.EncodeToString(s.PrivKey[:]) + s.PubKeyBase64 = base64.StdEncoding.EncodeToString(s.PubKey[:]) + s.BriefName = fmt.Sprintf("%s...%s", s.PubKeyBase64[0:4], s.PubKeyBase64[39:43]) + return &s +} + +// 生成用于ECDH的SM2公私钥对 +func GenerateSM2ECDHKeypair() (string, string) { + var err error + var pubKey [64]byte + var privKey [32]byte + + pKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return "", "" + } + copy(privKey[:32], pKey.Bytes()[:32]) // 私钥32 bytes + copy(pubKey[:64], pKey.PublicKey().Bytes()[1:65]) // 公钥64 bytes + + return base64.StdEncoding.EncodeToString(pubKey[:]), + base64.StdEncoding.EncodeToString(privKey[:]) +} + +func Base64DecodeSM2ECDHPrivateKey(privStr string) (*ecdh.PrivateKey, error) { + privKeyBytes, err := base64.StdEncoding.DecodeString(privStr) + if err != nil { + return nil, err + } + if len(privKeyBytes) != 32 { + return nil, fmt.Errorf("size incorrect") + } + privKey, err := ecdh.P256().NewPrivateKey(privKeyBytes) + if err != nil { + return nil, err + } + return privKey, nil +} + +func Base64DecodeSM2ECDHPublicKey(pubStr string) (*ecdh.PublicKey, error) { + pubKeyBytes, err := base64.StdEncoding.DecodeString(pubStr) + if err != nil { + return nil, err + } + if len(pubKeyBytes) != 64 { + return nil, fmt.Errorf("size incorrect") + } + buf := make([]byte, 65) + buf[0] = 4 // public key first byte means uncompressed + copy(buf[1:], pubKeyBytes[:]) + pubKey, err := ecdh.P256().NewPublicKey(buf[:]) + if err != nil { + return nil, err + } + + return pubKey, nil +} + +// 生成用于ECDSA的SM2公私钥对 +func GenerateSM2ECDSAKeypair() (*sm2.PrivateKey, string, string) { + var err error + var pubKeyBytes [64]byte + var privKeyBytes [32]byte + privKey := new(sm2.PrivateKey) + + for { + privKey, err = sm2.GenerateKey(rand.Reader) + if err == nil { + break + } + } + copy(privKeyBytes[:], privKey.D.Bytes()[:]) // 32 bytes D + copy(pubKeyBytes[:32], privKey.PublicKey.X.Bytes()[:]) // 32 bytes X + copy(pubKeyBytes[32:], privKey.PublicKey.Y.Bytes()[:]) // 32 bytes Y + + return privKey, + base64.StdEncoding.EncodeToString(pubKeyBytes[:]), + base64.StdEncoding.EncodeToString(privKeyBytes[:]) +} + +func Base64DecodeSM2ECDSAPrivateKey(pubKeyStr string, privKeyStr string) (*sm2.PrivateKey, error) { + privKeyBytes, err := base64.StdEncoding.DecodeString(privKeyStr) + if err != nil { + return nil, err + } + if len(privKeyBytes) != 32 { + return nil, fmt.Errorf("size incorrect") + } + pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) + if err != nil { + return nil, err + } + if len(pubKeyBytes) != 64 { + return nil, fmt.Errorf("size incorrect") + } + + privKey := &sm2.PrivateKey{} + privKey.D = new(big.Int) + privKey.D.SetBytes(privKeyBytes[:]) + + privKey.PublicKey.Curve = sm2.P256() + privKey.PublicKey.X = new(big.Int) + privKey.PublicKey.Y = new(big.Int) + privKey.PublicKey.X.SetBytes(pubKeyBytes[:32]) + privKey.PublicKey.Y.SetBytes(pubKeyBytes[32:]) + + return privKey, nil +} + +func Base64DecodeSM2ECDSAPublicKey(pubKeyStr string) (*ecdsa.PublicKey, error) { + pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) + if err != nil { + return nil, err + } + if len(pubKeyBytes) != 64 { + return nil, fmt.Errorf("size incorrect") + } + + pubKey := &ecdsa.PublicKey{ + Curve: sm2.P256(), + X: new(big.Int), + Y: new(big.Int), + } + + pubKey.X.SetBytes(pubKeyBytes[:32]) + pubKey.Y.SetBytes(pubKeyBytes[32:]) + + return pubKey, nil +} diff --git a/core/scheme/gmsm/header.go b/core/scheme/gmsm/header.go new file mode 100644 index 00000000..89d65205 --- /dev/null +++ b/core/scheme/gmsm/header.go @@ -0,0 +1,119 @@ +package gmsm + +import ( + "encoding/binary" + "unsafe" + + "github.com/OpenNHP/opennhp/utils" +) + +const ( + HeaderCommonSize = 24 + HashSize = 32 + GCMNonceSize = 12 + GCMTagSize = 16 + TimestampSize = 8 + HeaderSize = HeaderCommonSize + PublicKeySize + PublicKeySize + GCMTagSize + TimestampSize + GCMTagSize + HashSize +) + +type HeaderGmsm struct { + HeaderCommon [HeaderCommonSize]byte + Ephermeral [PublicKeySize]byte + Static [PublicKeySize + GCMTagSize]byte + Timestamp [TimestampSize + GCMTagSize]byte + HMAC [HashSize]byte +} + +// header flags (bit 0 - bit 11) +const ( + NHP_FLAG_EXTENDEDLENGTH = 1 << iota + NHP_FLAG_COMPRESS +) + +// cipher scheme combination (bit 11 - bit 15) +const ( + NHP_FLAG_SCHEME_GMSM = 0 << 12 +) + +// gmsm header implementations +func (h *HeaderGmsm) TypeAndPayloadSize() (t int, s int) { + preamble := binary.BigEndian.Uint32(h.HeaderCommon[0:4]) + tns := preamble ^ binary.BigEndian.Uint32(h.HeaderCommon[4:8]) + t = int((tns & 0xFFFF0000) >> 16) + s = int(tns & 0x0000FFFF) + return t, s +} + +func (h *HeaderGmsm) SetTypeAndPayloadSize(t int, s int) { + preamble := utils.GetRandomUint32() + t32 := uint32((t & 0x0000FFFF) << 16) + s32 := uint32(s & 0x0000FFFF) + tns := preamble ^ (s32 | t32) + binary.BigEndian.PutUint32(h.HeaderCommon[0:4], preamble) + binary.BigEndian.PutUint32(h.HeaderCommon[4:8], tns) +} + +func (h *HeaderGmsm) Size() int { + return HeaderSize +} + +func (h *HeaderGmsm) Version() (int, int) { + major := h.HeaderCommon[8] + minor := h.HeaderCommon[9] + return int(major), int(minor) +} + +func (h *HeaderGmsm) SetVersion(major int, minor int) { + h.HeaderCommon[8] = uint8(major) + h.HeaderCommon[9] = uint8(minor) +} + +func (h *HeaderGmsm) Flag() uint16 { + return binary.BigEndian.Uint16(h.HeaderCommon[10:12]) +} + +func (h *HeaderGmsm) SetFlag(flag uint16) { + flag |= uint16(NHP_FLAG_EXTENDEDLENGTH) + flag &= 0xF << 12 + flag |= NHP_FLAG_SCHEME_GMSM << 12 + binary.BigEndian.PutUint16(h.HeaderCommon[10:12], flag) +} + +func (h *HeaderGmsm) NonceBytes() []byte { + var nonce [GCMNonceSize]byte + copy(nonce[4:GCMNonceSize], h.HeaderCommon[16:24]) + return nonce[:] +} + +func (h *HeaderGmsm) SetCounter(counter uint64) { + binary.BigEndian.PutUint64(h.HeaderCommon[16:24], counter) +} + +func (h *HeaderGmsm) Counter() uint64 { + return binary.BigEndian.Uint64(h.HeaderCommon[16:24]) +} + +func (h *HeaderGmsm) Bytes() []byte { + pHeader := (*[HeaderSize]byte)(unsafe.Pointer(&h.HeaderCommon)) + return pHeader[:] +} + +func (h *HeaderGmsm) EphermeralBytes() []byte { + return h.Ephermeral[:] +} + +func (h *HeaderGmsm) StaticBytes() []byte { + return h.Static[:] +} + +func (h *HeaderGmsm) TimestampBytes() []byte { + return h.Timestamp[:] +} + +func (h *HeaderGmsm) IdentityBytes() []byte { + return nil +} + +func (h *HeaderGmsm) HMACBytes() []byte { + return h.HMAC[:] +} diff --git a/core/scheme/gmsm/responder.go b/core/scheme/gmsm/responder.go new file mode 100644 index 00000000..3038e818 --- /dev/null +++ b/core/scheme/gmsm/responder.go @@ -0,0 +1 @@ +package gmsm diff --git a/core/tcpconn.go b/core/tcpconn.go new file mode 100644 index 00000000..9a8bc959 --- /dev/null +++ b/core/tcpconn.go @@ -0,0 +1 @@ +package core diff --git a/nhp/transaction.go b/core/transaction.go similarity index 98% rename from nhp/transaction.go rename to core/transaction.go index 7cbc6efd..2f0268b5 100644 --- a/nhp/transaction.go +++ b/core/transaction.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "time" @@ -11,7 +11,7 @@ type LocalTransaction struct { transactionId uint64 connData *ConnectionData mad *MsgAssemblerData - NextPacketCh chan *UdpPacket // higher level entities should redirect packet to this channel + NextPacketCh chan *Packet // higher level entities should redirect packet to this channel ExternalMsgCh chan *PacketParserData // a channel to receive an external msg to complete the transaction timeout int } diff --git a/nhp/udpconn.go b/core/udpconn.go similarity index 87% rename from nhp/udpconn.go rename to core/udpconn.go index 491c3ea3..82db3b45 100644 --- a/nhp/udpconn.go +++ b/core/udpconn.go @@ -1,4 +1,4 @@ -package nhp +package core import ( "net" @@ -24,8 +24,8 @@ type ConnectionData struct { RemoteAddr *net.UDPAddr CookieStore *CookieStore TimeoutMs int - SendQueue chan *UdpPacket - RecvQueue chan *UdpPacket + SendQueue chan *Packet + RecvQueue chan *Packet BlockSignal chan struct{} SetTimeoutSignal chan struct{} StopSignal chan struct{} @@ -66,9 +66,9 @@ flush: for { select { case pkt := <-c.SendQueue: - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) case pkt := <-c.RecvQueue: - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) case <-c.BlockSignal: default: break flush @@ -91,10 +91,10 @@ func (c *ConnectionData) IsClosed() bool { return c.closed.Load() } -func (c *ConnectionData) ForwardOutboundPacket(pkt *UdpPacket) { +func (c *ConnectionData) ForwardOutboundPacket(pkt *Packet) { if c.IsClosed() { log.Warning("connection %s is closed, discard packet", c.RemoteAddr.String()) - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) return } @@ -103,14 +103,14 @@ func (c *ConnectionData) ForwardOutboundPacket(pkt *UdpPacket) { // fully encrypted packet will be forwarded to higher level entity for physical sending default: log.Critical("connection send channel is full, discard packet") - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) } } -func (c *ConnectionData) ForwardInboundPacket(pkt *UdpPacket) { +func (c *ConnectionData) ForwardInboundPacket(pkt *Packet) { if c.IsClosed() { log.Warning("connection %s is closed, discard packet", c.RemoteAddr.String()) - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) return } @@ -120,7 +120,7 @@ func (c *ConnectionData) ForwardInboundPacket(pkt *UdpPacket) { default: // non-blocking, just discard log.Critical("connection recv channel is full, discard packet") - c.Device.ReleaseUdpPacket(pkt) + c.Device.ReleasePoolPacket(pkt) } } diff --git a/nhp/crypto.go b/nhp/crypto.go deleted file mode 100644 index 7fff4934..00000000 --- a/nhp/crypto.go +++ /dev/null @@ -1,413 +0,0 @@ -package nhp - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/ecdsa" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "fmt" - "hash" - "math/big" - - "github.com/emmansun/gmsm/ecdh" - "github.com/emmansun/gmsm/sm2" - "github.com/emmansun/gmsm/sm3" - "github.com/emmansun/gmsm/sm4" - "golang.org/x/crypto/blake2s" - "golang.org/x/crypto/chacha20poly1305" - "golang.org/x/crypto/curve25519" -) - -type HashTypeEnum int - -const ( - HASH_BLAKE2S HashTypeEnum = iota - HASH_SM3 - HASH_SHA256 -) - -type EccTypeEnum int - -const ( - ECC_CURVE25519 EccTypeEnum = iota - ECC_SM2 -) - -type GcmTypeEnum int - -const ( - GCM_AES256 GcmTypeEnum = iota - GCM_SM4 - GCM_CHACHA20POLY1305 -) - -type CipherSuite struct { - EccType EccTypeEnum - HashType HashTypeEnum - GcmType GcmTypeEnum -} - -// init cipher suite -func NewCipherSuite(useGM bool) (ciphers *CipherSuite) { - // init cipher suite - if useGM { - ciphers = &CipherSuite{ - HashType: HASH_SM3, - EccType: ECC_SM2, - GcmType: GCM_SM4, - } - } else { - ciphers = &CipherSuite{ - HashType: HASH_BLAKE2S, - EccType: ECC_CURVE25519, - GcmType: GCM_AES256, - } - } - - return -} - -func (c *CipherSuite) IsUseGm() bool { - return c.EccType == ECC_SM2 -} - -func NewHash(t HashTypeEnum) (h hash.Hash) { - switch t { - case HASH_BLAKE2S: - h, _ = blake2s.New256(nil) - - case HASH_SM3: - h = sm3.New() - - case HASH_SHA256: - h = sha256.New() - } - - return h -} - -type Ecdh interface { - SetPrivateKey(prk []byte) error - PrivateKey() []byte - PublicKey() []byte - SharedSecret(pbk []byte) *[SymmetricKeySize]byte - Name() string - PrivateKeyBase64() string - PublicKeyBase64() string -} - -func ECDHFromKey(t EccTypeEnum, prk []byte) (e Ecdh) { - switch t { - case ECC_CURVE25519: - var c Curve25519ECDH - err := c.SetPrivateKey(prk) - if err != nil { - return nil - } - e = &c - - case ECC_SM2: - var s SM2ECDH - err := s.SetPrivateKey(prk) - if err != nil { - return nil - } - e = &s - } - - return e -} - -func NewECDH(t EccTypeEnum) (e Ecdh) { - var err error - switch t { - case ECC_CURVE25519: - key := make([]byte, PrivateKeySize) - _, err = rand.Read(key) - if err != nil { - return nil - } - // clamp - key[0] &= 248 - key[31] = (key[31] & 127) | 64 - var c Curve25519ECDH - c.SetPrivateKey(key) - e = &c - - case ECC_SM2: - var s SM2ECDH - s.prvK, err = ecdh.P256().GenerateKey(rand.Reader) - if err != nil { - return nil - } - copy(s.PrivKey[:], s.prvK.Bytes()) - copy(s.PubKey[:], s.prvK.PublicKey().Bytes()[1:1+PublicKeySizeEx]) - s.PrivKeyBase64 = base64.StdEncoding.EncodeToString(s.PrivKey[:]) - s.PubKeyBase64 = base64.StdEncoding.EncodeToString(s.PubKey[:]) - e = &s - } - - return e -} - -type Curve25519ECDH struct { - PrivKey [PrivateKeySize]byte - PubKey [PublicKeySize]byte - PrivKeyBase64 string - PubKeyBase64 string -} - -func (c *Curve25519ECDH) SetPrivateKey(prk []byte) (err error) { - copy(c.PrivKey[:], prk[:PrivateKeySize]) - pbk, err := curve25519.X25519(c.PrivKey[:], curve25519.Basepoint) - if err != nil { - return err - } - copy(c.PubKey[:], pbk) - c.PrivKeyBase64 = base64.StdEncoding.EncodeToString(c.PrivKey[:]) - c.PubKeyBase64 = base64.StdEncoding.EncodeToString(c.PubKey[:]) - - return nil -} - -func (c *Curve25519ECDH) PrivateKey() []byte { - return c.PrivKey[:] -} - -func (c *Curve25519ECDH) PrivateKeyBase64() string { - return c.PrivKeyBase64 -} - -func (c *Curve25519ECDH) PublicKey() []byte { - return c.PubKey[:] -} - -func (c *Curve25519ECDH) PublicKeyBase64() string { - return c.PubKeyBase64 -} - -func (c *Curve25519ECDH) SharedSecret(pbk []byte) *[SymmetricKeySize]byte { - if len(pbk) != PublicKeySize { - return nil - } - - key, err := curve25519.X25519(c.PrivKey[:], pbk) - if err != nil { - return nil - } - - var ss [SymmetricKeySize]byte - copy(ss[:], key) - return &ss -} - -func (c *Curve25519ECDH) Name() string { - return fmt.Sprintf("%s...%s", c.PubKeyBase64[0:4], c.PubKeyBase64[39:43]) -} - -type SM2ECDH struct { - PrivKey [PrivateKeySize]byte - PubKey [PublicKeySizeEx]byte - prvK *ecdh.PrivateKey - PrivKeyBase64 string - PubKeyBase64 string -} - -func (s *SM2ECDH) SetPrivateKey(prk []byte) (err error) { - copy(s.PrivKey[:], prk[:PrivateKeySize]) - s.prvK, err = ecdh.P256().NewPrivateKey(prk) - if err != nil { - return err - } - copy(s.PubKey[:], s.prvK.PublicKey().Bytes()[1:1+PublicKeySizeEx]) - s.PrivKeyBase64 = base64.StdEncoding.EncodeToString(s.PrivKey[:]) - s.PubKeyBase64 = base64.StdEncoding.EncodeToString(s.PubKey[:]) - - return nil -} - -func (s *SM2ECDH) PrivateKey() []byte { - return s.PrivKey[:] -} - -func (c *SM2ECDH) PrivateKeyBase64() string { - return c.PrivKeyBase64 -} - -func (s *SM2ECDH) PublicKey() []byte { - return s.PubKey[:] -} - -func (c *SM2ECDH) PublicKeyBase64() string { - return c.PubKeyBase64 -} - -func (s *SM2ECDH) SharedSecret(pbk []byte) *[SymmetricKeySize]byte { - if len(pbk) != PublicKeySizeEx { - return nil - } - - var pkBytes [1 + PublicKeySizeEx]byte - pkBytes[0] = 4 // uncompressed header - copy(pkBytes[1:1+PublicKeySizeEx], pbk[:PublicKeySizeEx]) - - pubK, err := ecdh.P256().NewPublicKey(pkBytes[:]) - if err != nil { - return nil - } - - key, err := s.prvK.ECDH(pubK) - if err != nil { - return nil - } - - var ss [SymmetricKeySize]byte - copy(ss[:], key) - return &ss -} - -func (s *SM2ECDH) Name() string { - return fmt.Sprintf("%s...%s", s.PubKeyBase64[0:4], s.PubKeyBase64[39:43]) -} - -func AeadFromKey(t GcmTypeEnum, key *[SymmetricKeySize]byte) (aead cipher.AEAD) { - switch t { - case GCM_AES256: - aesBlock, _ := aes.NewCipher(key[:]) - aead, _ = cipher.NewGCM(aesBlock) - - case GCM_SM4: - sm4Block, _ := sm4.NewCipher(key[8:24]) - aead, _ = cipher.NewGCM(sm4Block) - - case GCM_CHACHA20POLY1305: - aead, _ = chacha20poly1305.New(key[:]) - } - - return aead -} - -// 生成用于ECDH的SM2公私钥对 -func GenerateSM2ECDHKeypair() (string, string) { - var err error - var pubKey [64]byte - var privKey [32]byte - - pKey, err := ecdh.P256().GenerateKey(rand.Reader) - if err != nil { - return "", "" - } - copy(privKey[:32], pKey.Bytes()[:32]) // 私钥32 bytes - copy(pubKey[:64], pKey.PublicKey().Bytes()[1:65]) // 公钥64 bytes - - return base64.StdEncoding.EncodeToString(pubKey[:]), - base64.StdEncoding.EncodeToString(privKey[:]) -} - -func Base64DecodeSM2ECDHPrivateKey(privStr string) (*ecdh.PrivateKey, error) { - privKeyBytes, err := base64.StdEncoding.DecodeString(privStr) - if err != nil { - return nil, err - } - if len(privKeyBytes) != 32 { - return nil, fmt.Errorf("size incorrect") - } - privKey, err := ecdh.P256().NewPrivateKey(privKeyBytes) - if err != nil { - return nil, err - } - return privKey, nil -} - -func Base64DecodeSM2ECDHPublicKey(pubStr string) (*ecdh.PublicKey, error) { - pubKeyBytes, err := base64.StdEncoding.DecodeString(pubStr) - if err != nil { - return nil, err - } - if len(pubKeyBytes) != 64 { - return nil, fmt.Errorf("size incorrect") - } - buf := make([]byte, 65) - buf[0] = 4 // public key first byte means uncompressed - copy(buf[1:], pubKeyBytes[:]) - pubKey, err := ecdh.P256().NewPublicKey(buf[:]) - if err != nil { - return nil, err - } - - return pubKey, nil -} - -// 生成用于ECDSA的SM2公私钥对 -func GenerateSM2ECDSAKeypair() (*sm2.PrivateKey, string, string) { - var err error - var pubKeyBytes [64]byte - var privKeyBytes [32]byte - privKey := new(sm2.PrivateKey) - - for { - privKey, err = sm2.GenerateKey(rand.Reader) - if err == nil { - break - } - } - copy(privKeyBytes[:], privKey.D.Bytes()[:]) // 32 bytes D - copy(pubKeyBytes[:32], privKey.PublicKey.X.Bytes()[:]) // 32 bytes X - copy(pubKeyBytes[32:], privKey.PublicKey.Y.Bytes()[:]) // 32 bytes Y - - return privKey, - base64.StdEncoding.EncodeToString(pubKeyBytes[:]), - base64.StdEncoding.EncodeToString(privKeyBytes[:]) -} - -func Base64DecodeSM2ECDSAPrivateKey(pubKeyStr string, privKeyStr string) (*sm2.PrivateKey, error) { - privKeyBytes, err := base64.StdEncoding.DecodeString(privKeyStr) - if err != nil { - return nil, err - } - if len(privKeyBytes) != 32 { - return nil, fmt.Errorf("size incorrect") - } - pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) - if err != nil { - return nil, err - } - if len(pubKeyBytes) != 64 { - return nil, fmt.Errorf("size incorrect") - } - - privKey := &sm2.PrivateKey{} - privKey.D = new(big.Int) - privKey.D.SetBytes(privKeyBytes[:]) - - privKey.PublicKey.Curve = sm2.P256() - privKey.PublicKey.X = new(big.Int) - privKey.PublicKey.Y = new(big.Int) - privKey.PublicKey.X.SetBytes(pubKeyBytes[:32]) - privKey.PublicKey.Y.SetBytes(pubKeyBytes[32:]) - - return privKey, nil -} - -func Base64DecodeSM2ECDSAPublicKey(pubKeyStr string) (*ecdsa.PublicKey, error) { - pubKeyBytes, err := base64.StdEncoding.DecodeString(pubKeyStr) - if err != nil { - return nil, err - } - if len(pubKeyBytes) != 64 { - return nil, fmt.Errorf("size incorrect") - } - - pubKey := &ecdsa.PublicKey{ - Curve: sm2.P256(), - X: new(big.Int), - Y: new(big.Int), - } - - pubKey.X.SetBytes(pubKeyBytes[:32]) - pubKey.Y.SetBytes(pubKeyBytes[32:]) - - return pubKey, nil -} diff --git a/nhp/packet.go b/nhp/packet.go deleted file mode 100644 index 5fb46ecf..00000000 --- a/nhp/packet.go +++ /dev/null @@ -1,371 +0,0 @@ -package nhp - -import ( - "encoding/binary" - "fmt" - "unsafe" - - "github.com/OpenNHP/opennhp/utils" -) - -type HeaderTypeEnum int - -const ( - NHP_KPL = iota // general keepalive packet - NHP_KNK // agent sends knock to server - NHP_ACK // server replies knock status to agent - NHP_AOP // server asks door for operation - NHP_ART // door replies server for operation result - NHP_LST // agent requests server for listing services and applications - NHP_LRT // server replies to agent with services and applications result - NHP_COK // server sends cookie to agent - NHP_RKN // agent sends reknock to server - NHP_RLY // relay sends relayed packet to server - NHP_AOL // door sends online status to server - NHP_AAK // server sends ack to door after receving door's online status - NHP_OTP // agent requests server for one-time-password - NHP_REG // agent asks server for registering - NHP_RAK // server sends back ack when agent registers correctly - NHP_ACC // agent sends to door/resource for actual ip access - NHP_EXT // agent requests immediate disconnection -) - -var nhpHeaderTypeStrings []string = []string{ - "NHP-KPL", // general keepalive packet - "NHP-KNK", // agent sends knock to server - "NHP-ACK", // server replies knock status to agent - "NHP-AOP", // server asks door for operation - "NHP-ART", // door replies server for operation result - "NHP-LST", // agent requests server for listing services and applications - "NHP-LRT", // server replies to agent with services and applications result - "NHP-COK", // server sends cookie to agent - "NHP-RKN", // agent sends reknock to server - "NHP-RLY", // relay sends relayed packet to server - "NHP-AOL", // door sends online status to server - "NHP-AAK", // server sends ack to door after receving door's online status - "NHP-OTP", // agent requests server for one-time-password - "NHP-REG", // agent asks server for registering - "NHP-RAK", // server sends back ack when agent registers correctly - "NHP-ACC", // agent sends to door/resource for actual ip access - "NHP_EXT", // agent requests immediate disconnection -} - -func HeaderTypeToString(t int) string { - if t < len(nhpHeaderTypeStrings) { - return nhpHeaderTypeStrings[t] - } - return "UNKNOWN" -} - -func HeaderTypeToDeviceType(t int) int { - switch t { - case NHP_KNK, NHP_LST, NHP_RKN, NHP_OTP, NHP_REG, NHP_ACC, NHP_EXT: - return NHP_AGENT - - case NHP_ACK, NHP_AOP, NHP_LRT, NHP_COK, NHP_AAK, NHP_RAK: - return NHP_SERVER - - case NHP_AOL, NHP_ART: - return NHP_AC - - case NHP_RLY: - return NHP_RELAY - } - - return NHP_NO_DEVICE -} - -type HeaderFlagEnum int - -const ( - NHP_FLAG_EXTENDEDLENGTH = 1 << iota - NHP_FLAG_COMPRESS -) - -type NHPHeaderCommon struct { - Preamble uint32 - Type uint16 - Size uint16 - VerMajor uint8 - VerMinor uint8 - Flag uint16 - Reserved uint32 - Counter uint64 -} - -type NHPHeader struct { - HeaderCommon [HeaderCommonSize]byte - Ephermeral [PublicKeySize]byte - Static [PublicKeySize + GCMTagSize]byte - Timestamp [TimestampSize + GCMTagSize]byte - HMAC [HashSize]byte -} - -type NHPHeaderEx struct { - HeaderCommon [HeaderCommonSize]byte - Ephermeral [PublicKeySizeEx]byte - Static [PublicKeySizeEx + GCMTagSize]byte - Timestamp [TimestampSize + GCMTagSize]byte - HMAC [HashSize]byte -} - -type Header interface { - SetTypeAndPayloadSize(int, int) - TypeAndPayloadSize() (int, int) - Size() int - SetVersion(int, int) - Version() (int, int) - SetFlag(uint16) - Flag() uint16 - SetCounter(uint64) - Counter() uint64 - Bytes() []byte - NonceBytes() []byte - EphermeralBytes() []byte - StaticBytes() []byte - TimestampBytes() []byte - HMACBytes() []byte -} - -// NHPHeader implementations -func (h *NHPHeader) TypeAndPayloadSize() (t int, s int) { - preamble := binary.BigEndian.Uint32(h.HeaderCommon[0:4]) - tns := preamble ^ binary.BigEndian.Uint32(h.HeaderCommon[4:8]) - t = int((tns & 0xFFFF0000) >> 16) - s = int(tns & 0x0000FFFF) - return t, s -} - -func (h *NHPHeader) SetTypeAndPayloadSize(t int, s int) { - preamble := utils.GetRandomUint32() - t32 := uint32((t & 0x0000FFFF) << 16) - s32 := uint32(s & 0x0000FFFF) - tns := preamble ^ (s32 | t32) - binary.BigEndian.PutUint32(h.HeaderCommon[0:4], preamble) - binary.BigEndian.PutUint32(h.HeaderCommon[4:8], tns) -} - -func (h *NHPHeader) Size() int { - return HeaderSize -} - -func (h *NHPHeader) Version() (int, int) { - major := h.HeaderCommon[8] - minor := h.HeaderCommon[9] - return int(major), int(minor) -} - -func (h *NHPHeader) SetVersion(major int, minor int) { - h.HeaderCommon[8] = uint8(major) - h.HeaderCommon[9] = uint8(minor) -} - -func (h *NHPHeader) Flag() uint16 { - return binary.BigEndian.Uint16(h.HeaderCommon[10:12]) -} - -func (h *NHPHeader) SetFlag(flag uint16) { - flag &= ^uint16(NHP_FLAG_EXTENDEDLENGTH) - binary.BigEndian.PutUint16(h.HeaderCommon[10:12], flag) -} - -func (h *NHPHeader) NonceBytes() []byte { - var nonce [GCMNonceSize]byte - copy(nonce[4:GCMNonceSize], h.HeaderCommon[16:24]) - return nonce[:] -} - -func (h *NHPHeader) SetCounter(counter uint64) { - binary.BigEndian.PutUint64(h.HeaderCommon[16:24], counter) -} - -func (h *NHPHeader) Counter() uint64 { - return binary.BigEndian.Uint64(h.HeaderCommon[16:24]) -} - -func (h *NHPHeader) Bytes() []byte { - pHeader := (*[HeaderSize]byte)(unsafe.Pointer(&h.HeaderCommon)) - return pHeader[:] -} - -func (h *NHPHeader) EphermeralBytes() []byte { - return h.Ephermeral[:] -} - -func (h *NHPHeader) StaticBytes() []byte { - return h.Static[:] -} - -func (h *NHPHeader) TimestampBytes() []byte { - return h.Timestamp[:] -} - -func (h *NHPHeader) HMACBytes() []byte { - return h.HMAC[:] -} - -// NHPHeaderEx implementations -func (h *NHPHeaderEx) TypeAndPayloadSize() (t int, s int) { - preamble := binary.BigEndian.Uint32(h.HeaderCommon[0:4]) - tns := preamble ^ binary.BigEndian.Uint32(h.HeaderCommon[4:8]) - t = int((tns & 0xFFFF0000) >> 16) - s = int(tns & 0x0000FFFF) - return t, s -} - -func (h *NHPHeaderEx) SetTypeAndPayloadSize(t int, s int) { - preamble := utils.GetRandomUint32() - t32 := uint32((t & 0x0000FFFF) << 16) - s32 := uint32(s & 0x0000FFFF) - tns := preamble ^ (s32 | t32) - binary.BigEndian.PutUint32(h.HeaderCommon[0:4], preamble) - binary.BigEndian.PutUint32(h.HeaderCommon[4:8], tns) -} - -func (h *NHPHeaderEx) Size() int { - return HeaderSizeEx -} - -func (h *NHPHeaderEx) Version() (int, int) { - major := h.HeaderCommon[8] - minor := h.HeaderCommon[9] - return int(major), int(minor) -} - -func (h *NHPHeaderEx) SetVersion(major int, minor int) { - h.HeaderCommon[8] = uint8(major) - h.HeaderCommon[9] = uint8(minor) -} - -func (h *NHPHeaderEx) Flag() uint16 { - return binary.BigEndian.Uint16(h.HeaderCommon[10:12]) -} - -func (h *NHPHeaderEx) SetFlag(flag uint16) { - flag |= uint16(NHP_FLAG_EXTENDEDLENGTH) - binary.BigEndian.PutUint16(h.HeaderCommon[10:12], flag) -} - -func (h *NHPHeaderEx) NonceBytes() []byte { - var nonce [GCMNonceSize]byte - copy(nonce[4:GCMNonceSize], h.HeaderCommon[16:24]) - return nonce[:] -} - -func (h *NHPHeaderEx) SetCounter(counter uint64) { - binary.BigEndian.PutUint64(h.HeaderCommon[16:24], counter) -} - -func (h *NHPHeaderEx) Counter() uint64 { - return binary.BigEndian.Uint64(h.HeaderCommon[16:24]) -} - -func (h *NHPHeaderEx) Bytes() []byte { - pHeader := (*[HeaderSizeEx]byte)(unsafe.Pointer(&h.HeaderCommon)) - return pHeader[:] -} - -func (h *NHPHeaderEx) EphermeralBytes() []byte { - return h.Ephermeral[:] -} - -func (h *NHPHeaderEx) StaticBytes() []byte { - return h.Static[:] -} - -func (h *NHPHeaderEx) TimestampBytes() []byte { - return h.Timestamp[:] -} - -func (h *NHPHeaderEx) HMACBytes() []byte { - return h.HMAC[:] -} - -type PacketBuffer = [PacketBufferSize]byte - -// packet buffer pool -type PacketBufferPool struct { - pool *utils.WaitPool -} - -func (bp *PacketBufferPool) Init(max uint32) { - bp.pool = utils.NewWaitPool(max, func() any { return new(PacketBuffer) }) -} - -// must be called after Init() -func (bp *PacketBufferPool) Get() *PacketBuffer { - return bp.pool.Get().(*PacketBuffer) -} - -// must be called after Init() -func (bp *PacketBufferPool) Put(packet *PacketBuffer) { - bp.pool.Put(packet) -} - -type UdpPacket struct { - Buf *PacketBuffer - HeaderType int - KeepAfterSend bool // only applicable for sending - Packet []byte -} - -func (pkt *UdpPacket) Flag() uint16 { - return binary.BigEndian.Uint16(pkt.Packet[10:12]) -} - -func (pkt *UdpPacket) HeaderTypeAndSize() (t int, s int) { - preamble := binary.BigEndian.Uint32(pkt.Packet[0:4]) - tns := preamble ^ binary.BigEndian.Uint32(pkt.Packet[4:8]) - t = int((tns & 0xFFFF0000) >> 16) - s = int(tns & 0x0000FFFF) - pkt.HeaderType = t - - return t, s -} - -func (pkt *UdpPacket) Counter() uint64 { - return binary.BigEndian.Uint64(pkt.Packet[16:24]) -} - -func (d *Device) RecvPrecheck(pkt *UdpPacket) (int, int, error) { - var headerSize int - flag := pkt.Flag() - if flag&NHP_FLAG_EXTENDEDLENGTH == 0 { - headerSize = HeaderSize - } else { - headerSize = HeaderSizeEx - } - - // check type and payload size - t, s := pkt.HeaderTypeAndSize() - if t == NHP_KPL { - if s == 0 { - return t, s, nil - } else { - return t, s, fmt.Errorf("keepalive packet size is incorrect") - } - } - - if !d.CheckRecvHeaderType(t) { - return t, s, fmt.Errorf("packet header type does not match device") - } - - totalLen := len(pkt.Packet) - if totalLen != headerSize+s { - return t, s, fmt.Errorf("packet total size is incorrect") - } - - return t, s, nil -} - -func (d *Device) AllocateUdpPacket() *UdpPacket { - return &UdpPacket{Buf: d.pool.Get()} -} - -func (d *Device) ReleaseUdpPacket(pkt *UdpPacket) { - if pkt != nil && pkt.Buf != nil { - d.pool.Put(pkt.Buf) - pkt.Buf = nil - pkt.Packet = nil - } -} diff --git a/nhp/tcpconn.go b/nhp/tcpconn.go deleted file mode 100644 index c0e0f11d..00000000 --- a/nhp/tcpconn.go +++ /dev/null @@ -1 +0,0 @@ -package nhp diff --git a/release/nhp-device/nhpdevice.def b/release/nhp-device/nhpdevice.def new file mode 100644 index 00000000..e924b280 --- /dev/null +++ b/release/nhp-device/nhpdevice.def @@ -0,0 +1,14 @@ +LIBRARY + +EXPORTS + nhp_umi_device_init + nhp_umi_device_close + nhp_device_encrypt_data + nhp_device_decrypt_packet + nhp_device_set_overload + nhp_free_cstring + nhp_free_NhpResult + nhp_free_NhpEncryptResult + nhp_free_NhpDecryptResult + nhp_sm4_aead_encrypt + nhp_sm4_aead_decrypt \ No newline at end of file diff --git a/server/config.go b/server/config.go index 3ae06f14..a53ed74d 100644 --- a/server/config.go +++ b/server/config.go @@ -7,8 +7,8 @@ import ( "path/filepath" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/plugins" "github.com/OpenNHP/opennhp/utils" @@ -44,8 +44,8 @@ type HttpConfig struct { } type Peers struct { - ACs []*nhp.UdpPeer - Agents []*nhp.UdpPeer + ACs []*core.UdpPeer + Agents []*core.UdpPeer } func (s *UdpServer) loadBaseConfig() error { @@ -165,7 +165,7 @@ func (s *UdpServer) updateBaseConfig(file string) (err error) { if s.config.DisableAgentValidation != conf.DisableAgentValidation { if s.device != nil { - s.device.SetOption(nhp.DeviceOptions{ + s.device.SetOption(core.DeviceOptions{ DisableAgentPeerValidation: conf.DisableAgentValidation, }) } @@ -229,12 +229,12 @@ func (s *UdpServer) updateACPeers(file string) (err error) { // update var peers Peers - acPeerMap := make(map[string]*nhp.UdpPeer) + acPeerMap := make(map[string]*core.UdpPeer) if err := toml.Unmarshal(content, &peers); err != nil { log.Error("failed to unmarshal ac peer config: %v", err) } for _, p := range peers.ACs { - p.Type = nhp.NHP_AC + p.Type = core.NHP_AC s.device.AddPeer(p) acPeerMap[p.PublicKeyBase64()] = p } @@ -263,12 +263,12 @@ func (s *UdpServer) updateAgentPeers(file string) (err error) { } var peers Peers - agentPeerMap := make(map[string]*nhp.UdpPeer) + agentPeerMap := make(map[string]*core.UdpPeer) if err := toml.Unmarshal(content, &peers); err != nil { log.Error("failed to unmarshal agent peer config: %v", err) } for _, p := range peers.Agents { - p.Type = nhp.NHP_AGENT + p.Type = core.NHP_AGENT s.device.AddPeer(p) agentPeerMap[p.PublicKeyBase64()] = p } diff --git a/server/main/main.go b/server/main/main.go index c4e71b8b..cd9a8190 100644 --- a/server/main/main.go +++ b/server/main/main.go @@ -8,7 +8,7 @@ import ( "runtime/pprof" "syscall" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/server" "github.com/OpenNHP/opennhp/version" "github.com/urfave/cli/v2" @@ -39,11 +39,11 @@ func main() { &cli.BoolFlag{Name: "sm2", Value: false, DisableDefaultText: true, Usage: "generate sm2 keys"}, }, Action: func(c *cli.Context) error { - var e nhp.Ecdh + var e core.Ecdh if c.Bool("sm2") { - e = nhp.NewECDH(nhp.ECC_SM2) + e = core.NewECDH(core.ECC_SM2) } else { - e = nhp.NewECDH(nhp.ECC_CURVE25519) + e = core.NewECDH(core.ECC_CURVE25519) } pub := e.PublicKeyBase64() priv := e.PrivateKeyBase64() diff --git a/server/msghandler.go b/server/msghandler.go index b61208ee..73ef4f10 100644 --- a/server/msghandler.go +++ b/server/msghandler.go @@ -5,23 +5,23 @@ import ( "encoding/json" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" ) // HandleOTPRequest // Server will not respond to agent's otp request -func (s *UdpServer) HandleOTPRequest(ppd *nhp.PacketParserData) (err error) { +func (s *UdpServer) HandleOTPRequest(ppd *core.PacketParserData) (err error) { defer s.wg.Done() s.wg.Add(1) - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId addrStr := ppd.ConnData.RemoteAddr.String() otpMsg := &common.AgentOTPMsg{} err = json.Unmarshal(ppd.BodyMessage, otpMsg) if err != nil { - log.Error("server-agent(#%d@%s)[HandleOTPRequest] failed to parse %s message: %v", transactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("server-agent(#%d@%s)[HandleOTPRequest] failed to parse %s message: %v", transactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType), err) return err } @@ -50,11 +50,11 @@ func (s *UdpServer) HandleOTPRequest(ppd *nhp.PacketParserData) (err error) { // HandleRegisterRequest // Server will respond with success or error with NHP_RAK message -func (s *UdpServer) HandleRegisterRequest(ppd *nhp.PacketParserData) (err error) { +func (s *UdpServer) HandleRegisterRequest(ppd *core.PacketParserData) (err error) { defer s.wg.Done() s.wg.Add(1) - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId addrStr := ppd.ConnData.RemoteAddr.String() regMsg := &common.AgentRegisterMsg{} rakMsg := &common.ServerRegisterAckMsg{} @@ -62,7 +62,7 @@ func (s *UdpServer) HandleRegisterRequest(ppd *nhp.PacketParserData) (err error) func() { err = json.Unmarshal(ppd.BodyMessage, regMsg) if err != nil { - log.Error("server-agent(#%d@%s)[HandleRegisterRequest] failed to parse %s message: %v", transactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("server-agent(#%d@%s)[HandleRegisterRequest] failed to parse %s message: %v", transactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType), err) rakMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() rakMsg.ErrMsg = err.Error() return @@ -99,8 +99,8 @@ func (s *UdpServer) HandleRegisterRequest(ppd *nhp.PacketParserData) (err error) // send NHP_RAK message rakBytes, _ := json.Marshal(rakMsg) - rakMd := &nhp.MsgData{ - HeaderType: nhp.NHP_RAK, + rakMd := &core.MsgData{ + HeaderType: core.NHP_RAK, TransactionId: transactionId, Compress: true, PrevParserData: ppd, @@ -122,11 +122,11 @@ func (s *UdpServer) HandleRegisterRequest(ppd *nhp.PacketParserData) (err error) // HandleListRequest // Server will respond with success or error with NHP_LRT message -func (s *UdpServer) HandleListRequest(ppd *nhp.PacketParserData) (err error) { +func (s *UdpServer) HandleListRequest(ppd *core.PacketParserData) (err error) { defer s.wg.Done() s.wg.Add(1) - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId addrStr := ppd.ConnData.RemoteAddr.String() lstMsg := &common.AgentListMsg{} lrtMsg := &common.ServerListResultMsg{} @@ -134,7 +134,7 @@ func (s *UdpServer) HandleListRequest(ppd *nhp.PacketParserData) (err error) { func() { err = json.Unmarshal(ppd.BodyMessage, lstMsg) if err != nil { - log.Error("server-agent(#%d@%s)[HandleListRequest] failed to parse %s message: %v", transactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("server-agent(#%d@%s)[HandleListRequest] failed to parse %s message: %v", transactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType), err) lrtMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() lrtMsg.ErrMsg = err.Error() return @@ -169,8 +169,8 @@ func (s *UdpServer) HandleListRequest(ppd *nhp.PacketParserData) (err error) { }() lrtBytes, _ := json.Marshal(lrtMsg) - ackMd := &nhp.MsgData{ - HeaderType: nhp.NHP_LRT, + ackMd := &core.MsgData{ + HeaderType: core.NHP_LRT, TransactionId: transactionId, Compress: true, PrevParserData: ppd, @@ -190,24 +190,24 @@ func (s *UdpServer) HandleListRequest(ppd *nhp.PacketParserData) (err error) { return err } -func (s *UdpServer) HandleACOnline(ppd *nhp.PacketParserData) (err error) { +func (s *UdpServer) HandleACOnline(ppd *core.PacketParserData) (err error) { defer s.wg.Done() s.wg.Add(1) - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId addrStr := ppd.ConnData.RemoteAddr.String() aolMsg := &common.ACOnlineMsg{} err = json.Unmarshal(ppd.BodyMessage, aolMsg) if err != nil { - log.Error("server-ac(#%d@%s)[HandleACOnline] failed to parse %s message: %v", transactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("server-ac(#%d@%s)[HandleACOnline] failed to parse %s message: %v", transactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType), err) return err } acId := aolMsg.ACId acPubkeyBase64 := base64.StdEncoding.EncodeToString(ppd.RemotePubKey) s.acPeerMapMutex.Lock() - acPeer := s.acPeerMap[acPubkeyBase64] // door peer's recvAddr has already been updated by nhp packet parser + acPeer := s.acPeerMap[acPubkeyBase64] // ac peer's recvAddr has already been updated by nhp packet parser s.acPeerMapMutex.Unlock() acConn := &ACConn{ @@ -228,8 +228,8 @@ func (s *UdpServer) HandleACOnline(ppd *nhp.PacketParserData) (err error) { } aakBytes, _ := json.Marshal(aakMsg) - aakMd := &nhp.MsgData{ - HeaderType: nhp.NHP_AAK, + aakMd := &core.MsgData{ + HeaderType: core.NHP_AAK, TransactionId: transactionId, Compress: true, PrevParserData: ppd, diff --git a/server/nhpauth.go b/server/nhpauth.go index 47de7382..04c464d5 100644 --- a/server/nhpauth.go +++ b/server/nhpauth.go @@ -5,17 +5,17 @@ import ( "encoding/json" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" ) // HandleKnockRequest // Server will respond with success or error with NHP_ACK message -func (s *UdpServer) HandleKnockRequest(ppd *nhp.PacketParserData) (err error) { +func (s *UdpServer) HandleKnockRequest(ppd *core.PacketParserData) (err error) { defer s.wg.Done() s.wg.Add(1) - transactionId := ppd.SenderId + transactionId := ppd.SenderTrxId addrStr := ppd.ConnData.RemoteAddr.String() knkMsg := &common.AgentKnockMsg{} ackMsg := &common.ServerKnockAckMsg{ @@ -26,7 +26,7 @@ func (s *UdpServer) HandleKnockRequest(ppd *nhp.PacketParserData) (err error) { // parse knockMsg err = json.Unmarshal(ppd.BodyMessage, knkMsg) if err != nil { - log.Error("server-agent(#%d@%s)[HandleKnockRequest] failed to parse %s message: %v", transactionId, addrStr, nhp.HeaderTypeToString(ppd.HeaderType), err) + log.Error("server-agent(#%d@%s)[HandleKnockRequest] failed to parse %s message: %v", transactionId, addrStr, core.HeaderTypeToString(ppd.HeaderType), err) ackMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() ackMsg.ErrMsg = err.Error() return @@ -76,8 +76,8 @@ func (s *UdpServer) HandleKnockRequest(ppd *nhp.PacketParserData) (err error) { // send back knock ack response ackBytes, _ := json.Marshal(ackMsg) - ackMd := &nhp.MsgData{ - HeaderType: nhp.NHP_ACK, + ackMd := &core.MsgData{ + HeaderType: core.NHP_ACK, TransactionId: transactionId, // transactionId of the original knock request Compress: true, PrevParserData: ppd, diff --git a/server/plugins/example/main.go b/server/plugins/example/main.go index 76c890b7..ecec5b25 100644 --- a/server/plugins/example/main.go +++ b/server/plugins/example/main.go @@ -229,7 +229,7 @@ func authRegular(ctx *gin.Context, req *common.HttpKnockRequest, res *common.Res return nil, fmt.Errorf("user or password is incorrect") } - // interact with udp server for door operation + // interact with udp server for ac operation ackMsg, err := helper.AuthWithHttpCallbackFunc(req, res) if ackMsg == nil || ackMsg.ErrCode != common.ErrSuccess.ErrorCode() { log.Error("knock failed. ackMsg is nil") diff --git a/server/readme.md b/server/readme.md index 647d2d90..cc77f159 100644 --- a/server/readme.md +++ b/server/readme.md @@ -2,10 +2,9 @@ ## 架构设计 -**注:** 由于历史原因,此处的Door为NHP-AC的另一种表述,与NHP-AC意义相同。 -1. Server启动时监听特定端口,等待Agent和Door进行连接。并由Agent或Door主动触发向Server的通信。不存在Server向Agent或Door主动建立连接的情况,通常情况下这种连接会跨防火墙或NAT导致不能建立。 - - 特殊情况:Server在收到Agent发起的敲门处理时,鉴权后需要主动向Door发起开门请求,并等待回应。 +1. Server启动时监听特定端口,等待Agent和AC进行连接。并由Agent或AC主动触发向Server的通信。不存在Server向Agent或AC主动建立连接的情况,通常情况下这种连接会跨防火墙或NAT导致不能建立。 + - 特殊情况:Server在收到Agent发起的敲门处理时,鉴权后需要主动向AC发起开门请求,并等待回应。 2. 发送消息时,向**sendMsgCh**发送创建好的**MsgAssembler**(必须从已有连接中指定**ConnData**)。**MsgAssembler**经过加密后会从此连接发出 @@ -23,8 +22,8 @@ "listenPort": 62206, // whether to validate peer's public key when receiving NHP packet from agent. If true, server must have a pre-recorded public key pool (in "agents" field) of all allowed agents. If false, server skip public key validation, so it reduces secure level. "disableAgentValidation": false, - // list of preset allowed AC peers. only public key and expire time are needed. It has the same effect as AddDoorPeer() - "doors": [ + // list of preset allowed AC peers. only public key and expire time are needed. It has the same effect as AddACPeer() + "acs": [ { // type: NHP-AC "type": 3, diff --git a/server/udpserver.go b/server/udpserver.go index c0b43b95..e322a352 100644 --- a/server/udpserver.go +++ b/server/udpserver.go @@ -11,8 +11,8 @@ import ( "time" "github.com/OpenNHP/opennhp/common" + "github.com/OpenNHP/opennhp/core" "github.com/OpenNHP/opennhp/log" - "github.com/OpenNHP/opennhp/nhp" "github.com/OpenNHP/opennhp/plugins" "github.com/OpenNHP/opennhp/utils" "github.com/OpenNHP/opennhp/version" @@ -36,7 +36,7 @@ type UdpServer struct { localIp string localMac string - device *nhp.Device + device *core.Device httpServer *HttpServer wg sync.WaitGroup running atomic.Bool @@ -47,13 +47,13 @@ type UdpServer struct { remoteConnectionMap map[string]*UdpConn // indexed by remote UDP address agentPeerMapMutex sync.Mutex - agentPeerMap map[string]*nhp.UdpPeer // indexed by peer's public key base64 string + agentPeerMap map[string]*core.UdpPeer // indexed by peer's public key base64 string acConnectionMapMutex sync.Mutex acConnectionMap map[string]*ACConn // ac connection is indexed by remote IP address acPeerMapMutex sync.Mutex - acPeerMap map[string]*nhp.UdpPeer // indexed by peer's public key base64 string + acPeerMap map[string]*core.UdpPeer // indexed by peer's public key base64 string // block address management blockAddrMapMutex sync.Mutex @@ -76,8 +76,8 @@ type UdpServer struct { stop chan struct{} } - recvMsgCh <-chan *nhp.PacketParserData - sendMsgCh chan *nhp.MsgData + recvMsgCh <-chan *core.PacketParserData + sendMsgCh chan *core.MsgData } type BlockAddr struct { @@ -86,13 +86,13 @@ type BlockAddr struct { } type UdpConn struct { - ConnData *nhp.ConnectionData + ConnData *core.ConnectionData isACConnection bool // Immutable. Don't change it after creation. Conn object is also stored in acConnectionMap which is indexed by ACId } type ACConn struct { - ConnData *nhp.ConnectionData - ACPeer *nhp.UdpPeer + ConnData *core.ConnectionData + ACPeer *core.UdpPeer ACId string ServiceId string Apps []string @@ -161,10 +161,10 @@ func (s *UdpServer) Start(dirPath string, logLevel int) (err error) { return fmt.Errorf("private key parse error %v", err) } - option := &nhp.DeviceOptions{ + option := &core.DeviceOptions{ DisableAgentPeerValidation: s.config.DisableAgentValidation, } - s.device = nhp.NewDevice(nhp.NHP_SERVER, prk, option) + s.device = core.NewDevice(core.NHP_SERVER, prk, option) if s.device == nil { log.Critical("failed to create device %v\n", err) return fmt.Errorf("failed to create device %v", err) @@ -193,7 +193,7 @@ func (s *UdpServer) Start(dirPath string, logLevel int) (err error) { s.signals.stop = make(chan struct{}) s.recvMsgCh = s.device.DecryptedMsgQueue - s.sendMsgCh = make(chan *nhp.MsgData, nhp.SendQueueSize) + s.sendMsgCh = make(chan *core.MsgData, core.SendQueueSize) // start device routines s.device.Start() @@ -237,21 +237,21 @@ func (s *UdpServer) IsRunning() bool { return s.running.Load() } -func (s *UdpServer) SendPacket(pkt *nhp.UdpPacket, conn *UdpConn) (n int, err error) { +func (s *UdpServer) SendPacket(pkt *core.Packet, conn *UdpConn) (n int, err error) { defer func() { atomic.AddUint64(&s.stats.totalSendBytes, uint64(n)) atomic.StoreInt64(&conn.ConnData.LastLocalSendTime, time.Now().UnixNano()) if !pkt.KeepAfterSend { - s.device.ReleaseUdpPacket(pkt) + s.device.ReleasePoolPacket(pkt) } }() - pktType := nhp.HeaderTypeToString(pkt.HeaderType) - //log.Debug("Send [%s] packet (%s -> %s)", pktType, s.localAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Packet) - log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, s.listenAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - log.Evaluate("Send [%s] packet (%s -> %s), %d bytes", pktType, s.listenAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Packet)) - return s.listenConn.WriteToUDP(pkt.Packet, conn.ConnData.RemoteAddr) + pktType := core.HeaderTypeToString(pkt.HeaderType) + //log.Debug("Send [%s] packet (%s -> %s)", pktType, s.localAddr.String(), conn.ConnData.RemoteAddr.String(), pkt.Content) + log.Info("Send [%s] packet (%s -> %s), %d bytes", pktType, s.listenAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + log.Evaluate("Send [%s] packet (%s -> %s), %d bytes", pktType, s.listenAddr.String(), conn.ConnData.RemoteAddr.String(), len(pkt.Content)) + return s.listenConn.WriteToUDP(pkt.Content, conn.ConnData.RemoteAddr) } func (s *UdpServer) recvPacketRoutine() { @@ -271,12 +271,12 @@ func (s *UdpServer) recvPacketRoutine() { } // allocate a new packet buffer for every read - pkt := s.device.AllocateUdpPacket() + pkt := s.device.AllocatePoolPacket() // udp recv, blocking until packet arrives or conn.Close() n, remoteAddr, err := s.listenConn.ReadFromUDP(pkt.Buf[:]) if err != nil { - s.device.ReleaseUdpPacket(pkt) + s.device.ReleasePoolPacket(pkt) log.Error("Read from UDP error: %v\n", err) if n == 0 { // listenConn closed @@ -290,25 +290,25 @@ func (s *UdpServer) recvPacketRoutine() { atomic.AddUint64(&s.stats.totalRecvBytes, uint64(n)) // check minimal length - if n < nhp.HeaderSize { - s.device.ReleaseUdpPacket(pkt) + if n < core.HeaderSize { + s.device.ReleasePoolPacket(pkt) log.Error("Received UDP packet from %s is too short, discard", addrStr) continue } // check if it is from blocked address if s.IsBlockAddr(remoteAddr) { - s.device.ReleaseUdpPacket(pkt) + s.device.ReleasePoolPacket(pkt) log.Critical("Remote address %s is being blocked at the moment, discard.", addrStr) continue } recvTime := time.Now().UnixNano() - pkt.Packet = pkt.Buf[:n] - //log.Trace("receive udp packet (%s -> %s): %+v", addrStr, s.listenAddr.String(), pkt.Packet) + pkt.Content = pkt.Buf[:n] + //log.Trace("receive udp packet (%s -> %s): %+v", addrStr, s.listenAddr.String(), pkt.Content) typ, _, err := s.device.RecvPrecheck(pkt) // this check also records packet header type - msgType := nhp.HeaderTypeToString(typ) + msgType := core.HeaderTypeToString(typ) log.Info("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, s.listenAddr.String(), n) log.Evaluate("Receive [%s] packet (%s -> %s), %d bytes", msgType, addrStr, s.listenAddr.String(), n) if err != nil { @@ -317,7 +317,7 @@ func (s *UdpServer) recvPacketRoutine() { if preCheckThreats[addrStr] > PreCheckThreatCountBeforeBlock { s.AddBlockAddr(remoteAddr) } - s.device.ReleaseUdpPacket(pkt) + s.device.ReleasePoolPacket(pkt) log.Warning("Receive [%s] packet (%s -> %s), precheck error: %v", msgType, addrStr, s.listenAddr.String(), err) log.Evaluate("Receive [%s] packet (%s -> %s) precheck error: %v", msgType, addrStr, s.listenAddr.String(), err) continue @@ -342,27 +342,27 @@ func (s *UdpServer) recvPacketRoutine() { } else if len(s.remoteConnectionMap) >= MaxConcurrentConnection { s.remoteConnectionMapMutex.Unlock() log.Critical("Reached maximum concurrent connection. Discard new packet from addr: %s\n", addrStr) - s.device.ReleaseUdpPacket(pkt) + s.device.ReleasePoolPacket(pkt) continue } s.remoteConnectionMapMutex.Unlock() - isACConn := pkt.HeaderType == nhp.NHP_AOL + isACConn := pkt.HeaderType == core.NHP_AOL conn = &UdpConn{ isACConnection: isACConn, } // setup new routine for connection - conn.ConnData = &nhp.ConnectionData{ + conn.ConnData = &core.ConnectionData{ InitTime: recvTime, LastLocalRecvTime: recvTime, // not in multithreaded yet, directly assign value Device: s.device, LocalAddr: s.listenAddr, RemoteAddr: remoteAddr, - CookieStore: &nhp.CookieStore{}, - RemoteTransactionMap: make(map[uint64]*nhp.RemoteTransaction), + CookieStore: &core.CookieStore{}, + RemoteTransactionMap: make(map[uint64]*core.RemoteTransaction), TimeoutMs: DefaultAgentConnectionTimeoutMs, - SendQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), - RecvQueue: make(chan *nhp.UdpPacket, PacketQueueSizePerConnection), + SendQueue: make(chan *core.Packet, PacketQueueSizePerConnection), + RecvQueue: make(chan *core.Packet, PacketQueueSizePerConnection), BlockSignal: make(chan struct{}), SetTimeoutSignal: make(chan struct{}), StopSignal: make(chan struct{}), @@ -452,11 +452,11 @@ func (s *UdpServer) connectionRoutine(conn *UdpConn) { if pkt == nil { continue } - log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Packet), addrStr) + log.Debug("Received udp packet len [%d] from addr: %s\n", len(pkt.Content), addrStr) // process keepalive packet - if pkt.HeaderType == nhp.NHP_KPL { - s.device.ReleaseUdpPacket(pkt) + if pkt.HeaderType == core.NHP_KPL { + s.device.ReleasePoolPacket(pkt) log.Info("Receive [NHP_KPL] message (%s -> %s)", addrStr, s.listenAddr.String()) continue } @@ -471,7 +471,7 @@ func (s *UdpServer) connectionRoutine(conn *UdpConn) { } } - pd := &nhp.PacketData{ + pd := &core.PacketData{ BasePacket: pkt, ConnData: conn.ConnData, InitTime: atomic.LoadInt64(&conn.ConnData.LastLocalRecvTime), @@ -559,7 +559,7 @@ func (s *UdpServer) sendMessageRoutine() { } if md.PrevParserData != nil && s.device.IsTransactionResponse(md.HeaderType) { // forward to a specific transaction - transaction := md.ConnData.FindRemoteTransaction(md.PrevParserData.SenderId) + transaction := md.ConnData.FindRemoteTransaction(md.PrevParserData.SenderTrxId) if transaction != nil { transaction.NextMsgCh <- md continue @@ -593,29 +593,29 @@ func (s *UdpServer) recvMessageRoutine() { } switch ppd.HeaderType { - case nhp.NHP_KNK, nhp.NHP_RKN, nhp.NHP_EXT: + case core.NHP_KNK, core.NHP_RKN, core.NHP_EXT: // aynchronously process knock messages with ack response go s.HandleKnockRequest(ppd) - case nhp.NHP_AOL: + case core.NHP_AOL: // synchronously block and deal with NHP_DOL to ensure future ac messages will be correctly processed. Don't use go routine s.HandleACOnline(ppd) - case nhp.NHP_OTP: + case core.NHP_OTP: go s.HandleOTPRequest(ppd) - case nhp.NHP_REG: + case core.NHP_REG: go s.HandleRegisterRequest(ppd) - case nhp.NHP_LST: + case core.NHP_LST: go s.HandleListRequest(ppd) } } } } -func (s *UdpServer) AddAgentPeer(agent *nhp.UdpPeer) { - if agent.DeviceType() == nhp.NHP_AGENT { +func (s *UdpServer) AddAgentPeer(agent *core.UdpPeer) { + if agent.DeviceType() == core.NHP_AGENT { s.device.AddPeer(agent) s.agentPeerMapMutex.Lock() s.agentPeerMap[agent.PublicKeyBase64()] = agent @@ -623,8 +623,8 @@ func (s *UdpServer) AddAgentPeer(agent *nhp.UdpPeer) { } } -func (s *UdpServer) AddACPeer(acPeer *nhp.UdpPeer) { - if acPeer.DeviceType() == nhp.NHP_AC { +func (s *UdpServer) AddACPeer(acPeer *core.UdpPeer) { + if acPeer.DeviceType() == core.NHP_AC { s.device.AddPeer(acPeer) s.acPeerMapMutex.Lock() s.acPeerMap[acPeer.PublicKeyBase64()] = acPeer @@ -790,14 +790,14 @@ func (s *UdpServer) processACOperation(knkMsg *common.AgentKnockMsg, conn *ACCon } aopBytes, _ := json.Marshal(aopMsg) - aopMd := &nhp.MsgData{ + aopMd := &core.MsgData{ ConnData: conn.ConnData, - HeaderType: nhp.NHP_AOP, + HeaderType: core.NHP_AOP, TransactionId: s.device.NextCounterIndex(), Compress: true, PeerPk: conn.ACPeer.PublicKey(), Message: aopBytes, - ResponseMsgCh: make(chan *nhp.PacketParserData), + ResponseMsgCh: make(chan *core.PacketParserData), } if !s.IsRunning() { @@ -823,8 +823,8 @@ func (s *UdpServer) processACOperation(knkMsg *common.AgentKnockMsg, conn *ACCon return } - if acPpd.HeaderType != nhp.NHP_ART { - log.Error("server-agent(%s@%s)-ac(%s#%d@%s)[processACOperation] response has wrong type: %s", knkMsg.UserId, srcAddr.String(), conn.ACId, aopMd.TransactionId, acAddrStr, nhp.HeaderTypeToString(acPpd.HeaderType)) + if acPpd.HeaderType != core.NHP_ART { + log.Error("server-agent(%s@%s)-ac(%s#%d@%s)[processACOperation] response has wrong type: %s", knkMsg.UserId, srcAddr.String(), conn.ACId, aopMd.TransactionId, acAddrStr, core.HeaderTypeToString(acPpd.HeaderType)) err = common.ErrTransactionRepliedWithWrongType artMsg.ErrCode = common.ErrTransactionRepliedWithWrongType.ErrorCode() artMsg.ErrMsg = err.Error() @@ -833,7 +833,7 @@ func (s *UdpServer) processACOperation(knkMsg *common.AgentKnockMsg, conn *ACCon err = json.Unmarshal(acPpd.BodyMessage, artMsg) if err != nil { - log.Error("server-agent(%s@%s)-ac(%s#%d@%s)[processACOperation] failed to parse %s message: %v", knkMsg.UserId, srcAddr.String(), conn.ACId, aopMd.TransactionId, acAddrStr, nhp.HeaderTypeToString(acPpd.HeaderType), err) + log.Error("server-agent(%s@%s)-ac(%s#%d@%s)[processACOperation] failed to parse %s message: %v", knkMsg.UserId, srcAddr.String(), conn.ACId, aopMd.TransactionId, acAddrStr, core.HeaderTypeToString(acPpd.HeaderType), err) artMsg.ErrCode = common.ErrJsonParseFailed.ErrorCode() artMsg.ErrMsg = err.Error() return @@ -887,7 +887,7 @@ func (s *UdpServer) handleNhpOpenResource(req *common.NhpAuthRequest, res *commo defer acWg.Done() openTime := res.OpenTime - if knkMsg.HeaderType == nhp.NHP_EXT { + if knkMsg.HeaderType == core.NHP_EXT { openTime = 1 // timeout in 1 second } artMsg, _ := s.processACOperation(knkMsg, acConn, srcAddr, addrs, openTime) @@ -926,7 +926,7 @@ func (s *UdpServer) handleNhpOpenResource(req *common.NhpAuthRequest, res *commo return ackMsg, nil } -func (us *UdpServer) NewNhpServerHelper(ppd *nhp.PacketParserData) *plugins.NhpServerPluginHelper { +func (us *UdpServer) NewNhpServerHelper(ppd *core.PacketParserData) *plugins.NhpServerPluginHelper { h := &plugins.NhpServerPluginHelper{} h.StopSignal = ppd.ConnData.StopSignal diff --git a/test/ecdh_test.go b/test/ecdh_test.go index 0028517d..51793b8a 100644 --- a/test/ecdh_test.go +++ b/test/ecdh_test.go @@ -5,18 +5,18 @@ import ( "fmt" "testing" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" ) func TestCurve25519Keys(t *testing.T) { - e := nhp.NewECDH(nhp.ECC_CURVE25519) + e := core.NewECDH(core.ECC_CURVE25519) fmt.Printf("Private key: %s\n", e.PrivateKeyBase64()) fmt.Printf("Public key: %s\n", e.PublicKeyBase64()) } func TestSM2Keys(t *testing.T) { - e := nhp.NewECDH(nhp.ECC_SM2) + e := core.NewECDH(core.ECC_SM2) fmt.Printf("Private key: %s\n", e.PrivateKeyBase64()) fmt.Printf("Public key: %s\n", e.PublicKeyBase64()) @@ -25,17 +25,17 @@ func TestSM2Keys(t *testing.T) { func TestPublicKeys(t *testing.T) { //prk, err := base64.StdEncoding.DecodeString("kgvvQaBGfHNWCbZMkFWS1K07BgRXlnOo7CHTZF1bsmI=") // server //prk, err := base64.StdEncoding.DecodeString("2kRXjwV9zAUMc0Vf0jl984q2p9EiyjbAMUPKNu517z4=") // agent - prk, err := base64.StdEncoding.DecodeString("D2bieOaJarsM9euBBfSs/Ky8g/X6lBQ73NmP55CMgds=") // door + prk, err := base64.StdEncoding.DecodeString("D2bieOaJarsM9euBBfSs/Ky8g/X6lBQ73NmP55CMgds=") // ac if err != nil { fmt.Printf("Private key decode error\n") return } - curvee := nhp.ECDHFromKey(nhp.ECC_CURVE25519, prk) + curvee := core.ECDHFromKey(core.ECC_CURVE25519, prk) if curvee == nil { fmt.Printf("Wrong private key\n") return } - sm2e := nhp.ECDHFromKey(nhp.ECC_SM2, prk) + sm2e := core.ECDHFromKey(core.ECC_SM2, prk) if sm2e == nil { fmt.Printf("Wrong private key\n") return @@ -46,17 +46,17 @@ func TestPublicKeys(t *testing.T) { } func TestPeer(t *testing.T) { - server := &nhp.UdpPeer{ + server := &core.UdpPeer{ Ip: "192.168.2.27", Port: 62206, PubKeyBase64: "c0HALYy3433SqJmfN0JpRk1Q6H7xh84MAg89jYtRrQM=", ExpireTime: 1716345064, - Type: nhp.NHP_SERVER, + Type: core.NHP_SERVER, } - var p *nhp.UdpPeer = (*nhp.UdpPeer)(server) + var p *core.UdpPeer = (*core.UdpPeer)(server) - var peer nhp.Peer = p + var peer core.Peer = p fmt.Printf("Pub key %s, addr %s, name %s\n", peer.PublicKeyBase64(), peer.SendAddr().String(), peer.Name()) } diff --git a/test/ecdsa_test.go b/test/ecdsa_test.go index 61f22172..dc009b86 100644 --- a/test/ecdsa_test.go +++ b/test/ecdsa_test.go @@ -7,7 +7,8 @@ import ( "fmt" "testing" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" + "github.com/OpenNHP/opennhp/core/scheme/gmsm" "github.com/emmansun/gmsm/sm2" ) @@ -70,7 +71,7 @@ func TestSM2ECDSAKeysSerializeAndDeserialize(t *testing.T) { fmt.Printf("Private key: %s\n", hex.EncodeToString(privKey[:])) plainText := "This is a test for sm2 ecdsa keys serialization" - hash := nhp.NewHash(nhp.HASH_SHA256) + hash := core.NewHash(core.HASH_SHA256) hash.Write([]byte(plainText)) hashedBytes := hash.Sum(nil) fmt.Printf("hashed hex: %s, length: %d\n", hex.EncodeToString(hashedBytes), len(hashedBytes)) @@ -100,7 +101,7 @@ func TestSM2ECDSAKeysSerializeAndDeserialize(t *testing.T) { } fmt.Printf("Decypted plaintext: %s\n", decrypted) - privKey1, err := nhp.Base64DecodeSM2ECDSAPrivateKey(pubStr, privStr) + privKey1, err := gmsm.Base64DecodeSM2ECDSAPrivateKey(pubStr, privStr) if err != nil { fmt.Printf("decode priv key error: %v\n", err) return @@ -113,7 +114,7 @@ func TestSM2ECDSAKeysSerializeAndDeserialize(t *testing.T) { } fmt.Printf("Decypted plaintext1: %s\n", decrypted1) - pubKey1, err := nhp.Base64DecodeSM2ECDSAPublicKey(pubStr) + pubKey1, err := gmsm.Base64DecodeSM2ECDSAPublicKey(pubStr) if err != nil { fmt.Printf("decode pub key error: %v\n", err) return @@ -129,7 +130,7 @@ func TestKeyDeserialization(t *testing.T) { pubBytes, _ := hex.DecodeString(pubHexStr) privBytes, _ := hex.DecodeString(privHexStr) - privKey, err := nhp.Base64DecodeSM2ECDSAPrivateKey(base64.StdEncoding.EncodeToString(pubBytes), base64.StdEncoding.EncodeToString(privBytes)) + privKey, err := gmsm.Base64DecodeSM2ECDSAPrivateKey(base64.StdEncoding.EncodeToString(pubBytes), base64.StdEncoding.EncodeToString(privBytes)) if err != nil { fmt.Printf("decode failed %v\n", err) return @@ -150,11 +151,11 @@ func TestKeyDeserialization(t *testing.T) { } func TestECDHForECDSA(t *testing.T) { - pubStr, privStr := nhp.GenerateSM2ECDHKeypair() + pubStr, privStr := gmsm.GenerateSM2ECDHKeypair() fmt.Printf("Public key: %s\n", pubStr) fmt.Printf("Private key: %s\n", privStr) - sm2PrivKey, err := nhp.Base64DecodeSM2ECDSAPrivateKey(pubStr, privStr) + sm2PrivKey, err := gmsm.Base64DecodeSM2ECDSAPrivateKey(pubStr, privStr) if err != nil { fmt.Printf("decode error: %v\n", err) return diff --git a/test/packet_test.go b/test/packet_test.go index 8e5e6848..793b58c2 100644 --- a/test/packet_test.go +++ b/test/packet_test.go @@ -7,13 +7,15 @@ import ( "testing" "unsafe" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" + "github.com/OpenNHP/opennhp/core/scheme/curve" + "github.com/OpenNHP/opennhp/core/scheme/gmsm" ) func TestHeaderTypeAndSize(t *testing.T) { - pkt := &nhp.UdpPacket{ - //Packet: []byte{0x18, 0xca, 0xba, 0xa6, 0x18, 0xcb, 0xba, 0xa4}, - Packet: []byte{91, 89, 55, 86, 91, 88, 55, 25}, + pkt := &core.Packet{ + //Content: []byte{0x18, 0xca, 0xba, 0xa6, 0x18, 0xcb, 0xba, 0xa4}, + Content: []byte{91, 89, 55, 86, 91, 88, 55, 25}, } tp, sz := pkt.HeaderTypeAndSize() @@ -24,27 +26,27 @@ func TestHeaderTypeAndSize(t *testing.T) { func TestHMAC(t *testing.T) { buf := []byte{95, 205, 121, 55, 95, 204, 121, 100, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 115, 222, 224, 148, 163, 67, 89, 253, 194, 76, 203, 140, 48, 126, 226, 192, 141, 20, 34, 116, 14, 189, 159, 83, 219, 82, 88, 229, 146, 21, 229, 223, 208, 164, 174, 217, 154, 219, 90, 190, 140, 27, 9, 52, 89, 155, 197, 189, 145, 46, 69, 230, 45, 25, 127, 121, 196, 37, 112, 130, 155, 240, 47, 83, 25, 151, 82, 247, 255, 146, 54, 40, 8, 22, 33, 92, 112, 85, 158, 43, 170, 58, 165, 12, 161, 97, 195, 67, 178, 12, 205, 119, 98, 161, 5, 238, 75, 188, 12, 65, 35, 195, 197, 71, 12, 24, 0, 141, 27, 135, 228, 196, 136, 190, 195, 72, 246, 86, 65, 145, 95, 234, 80, 177, 91, 237, 186, 212, 231, 49, 118, 236, 156, 232, 5, 131, 218, 129, 213, 199, 46, 141, 47, 198, 4, 205, 31, 72, 91, 103, 125, 216, 54, 233, 222, 93, 203, 62, 96, 215, 42, 53, 147, 115, 69, 35, 151, 126, 249, 10, 38, 46, 89, 13, 146, 107, 14, 110, 109, 159, 19, 82, 95, 111, 104, 36, 251, 135, 148, 88, 231, 197, 131, 50, 254, 254, 249, 112, 125, 237, 19, 218, 198, 210, 207, 83, 75, 27, 117, 46, 176, 73, 65, 151, 40, 136, 133, 59, 32, 57, 51, 238, 222, 95, 134, 201, 21, 241, 153, 1, 176, 152, 179, 88, 118, 200, 130, 222, 210, 212, 11, 69, 229, 7, 56, 208, 241, 37, 148, 19, 111, 80, 221, 238, 247, 38, 88, 204, 43, 42, 13, 215, 25, 12, 100, 131, 34, 113, 100, 142, 170, 29, 20, 24, 196, 242, 46, 101, 3, 253, 111, 104, 25} - var header nhp.Header - var ciphers *nhp.CipherSuite - var serverEcdh nhp.Ecdh + var header core.Header + var ciphers *core.CipherSuite + var serverEcdh core.Ecdh prk, _ := base64.StdEncoding.DecodeString("kgvvQaBGfHNWCbZMkFWS1K07BgRXlnOo7CHTZF1bsmI=") flag := binary.BigEndian.Uint16(buf[10:12]) - if flag&nhp.NHP_FLAG_EXTENDEDLENGTH == 0 { - header = (*nhp.NHPHeader)(unsafe.Pointer(&buf[0])) - ciphers = nhp.NewCipherSuite(false) - serverEcdh = nhp.ECDHFromKey(ciphers.EccType, prk) + if flag&core.NHP_FLAG_EXTENDEDLENGTH == 0 { + header = (*curve.HeaderCurve)(unsafe.Pointer(&buf[0])) + ciphers = core.NewCipherSuite(core.CIPHER_SCHEME_CURVE) + serverEcdh = core.ECDHFromKey(ciphers.EccType, prk) } else { - header = (*nhp.NHPHeaderEx)(unsafe.Pointer(&buf[0])) - ciphers = nhp.NewCipherSuite(true) - serverEcdh = nhp.ECDHFromKey(ciphers.EccType, prk) + header = (*gmsm.HeaderGmsm)(unsafe.Pointer(&buf[0])) + ciphers = core.NewCipherSuite(core.CIPHER_SCHEME_GMSM) + serverEcdh = core.ECDHFromKey(ciphers.EccType, prk) } - hmacHash := nhp.NewHash(ciphers.HashType) - hmacHash.Write([]byte(nhp.InitialHashString)) + hmacHash := core.NewHash(ciphers.HashType) + hmacHash.Write([]byte(core.InitialHashString)) hmacHash.Write(serverEcdh.PublicKey()) - hmacHash.Write(buf[0 : header.Size()-nhp.HashSize]) + hmacHash.Write(buf[0 : header.Size()-core.HashSize]) calculatedHmac := hmacHash.Sum(nil) fmt.Printf("%v\n", calculatedHmac) diff --git a/test/toml_test.go b/test/toml_test.go index 1bbf729d..3681f310 100644 --- a/test/toml_test.go +++ b/test/toml_test.go @@ -7,7 +7,7 @@ import ( "github.com/OpenNHP/opennhp/ac" "github.com/OpenNHP/opennhp/common" - "github.com/OpenNHP/opennhp/nhp" + "github.com/OpenNHP/opennhp/core" "github.com/fsnotify/fsnotify" toml "github.com/pelletier/go-toml/v2" "github.com/spf13/viper" @@ -18,10 +18,10 @@ func TestTomlUnmarshal(t *testing.T) { a = "abc" B = "aBc" C = "abC" - ACId = "test.clouddeep.cn-door" + ACId = "test.clouddeep.cn-ac" PrivateKey = "+B0RLGbe+nknJBZ0Fjt7kCBWfSTUttbUqkGteLfIp30=" IpPassMode = 0 - AuthServiceId = "nhp.clouddeep.cn" + AuthServiceId = "core.clouddeep.cn" ResourceIds = ["test.clouddeep.cn"] OrganizationId = "5f3e36149fa95c0414408ad4" @@ -53,7 +53,7 @@ func TestTomlUnmarshal(t *testing.T) { AuthServiceId string ResourceIds []string OrganizationId string - Servers []*nhp.UdpPeer + Servers []*core.UdpPeer Data map[string]any } var Obj obj @@ -170,7 +170,7 @@ func TestUdpServerTomlViperHandling(t *testing.T) { } type acPeers struct { - ACs []*nhp.UdpPeer + ACs []*core.UdpPeer } var peers acPeers diff --git a/utils/crypto_test.go b/utils/crypto_test.go index 3e88116b..67d898eb 100644 --- a/utils/crypto_test.go +++ b/utils/crypto_test.go @@ -22,8 +22,8 @@ func TestAesD(t *testing.T) { fmt.Println(a) } -func TestGenerateDoorLicense(t *testing.T) { - var msh = `{"door":{"id":"6b5ce2e6-f8d8-d298-fa70-32cd51710fd6","private_key":"IHZyCkX2CFmvk6pISUI7RoEA31pYZrmKDzyjAa6qd0Q="},"server":{"host":"127.0.0.1:8081","public_key":"5/zceEX6OP38JRJMRIChWsQdyV9UgOKzdEahWwq7rDU="},"expired":1688633095000000,"create_time":1683362695000000}` +func TestGenerateACLicense(t *testing.T) { + var msh = `{"ac":{"id":"6b5ce2e6-f8d8-d298-fa70-32cd51710fd6","private_key":"IHZyCkX2CFmvk6pISUI7RoEA31pYZrmKDzyjAa6qd0Q="},"server":{"host":"127.0.0.1:8081","public_key":"5/zceEX6OP38JRJMRIChWsQdyV9UgOKzdEahWwq7rDU="},"expired":1688633095000000,"create_time":1683362695000000}` ens, err := AesEncrypt(msh) if err != nil {