Skip to content

Commit 05448cc

Browse files
authored
Implementation of smart data policy
1. Implement wasm engine with wazero. 2. To simplify the writing of smart data policy, implement smart data policy template based on Golang, and similar template can also be implemented by other programming language which support to be compiled into wasm. 3. Integrate smart data policy interfaces into nhp-agent and nhp-server. Co-authored-by: wenhulove333@163.com <Zhang Wenhu>
1 parent d209aba commit 05448cc

File tree

22 files changed

+1014
-166
lines changed

22 files changed

+1014
-166
lines changed

endpoints/agent/main/main.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,24 @@ func main() {
7878
Name: "dhp",
7979
Usage: "create and dhp agent process for NHP protocol",
8080
Flags: []cli.Flag{
81-
&cli.StringFlag{Name: "ztdo", Value: "", Usage: "Ztdo file path", Required: true},
82-
&cli.StringFlag{Name: "output", Value: "", Usage: "Decrypted file output path", Required: true},
81+
&cli.StringFlag{Name: "ztdo", Value: "", Usage: "Ztdo file path"},
82+
&cli.StringFlag{Name: "ztdo-id", Value: "", Usage: "Identifier of ztdo"},
83+
&cli.StringFlag{Name: "output", Value: "", Usage: "Decrypted file output path"},
84+
},
85+
Before: func(c *cli.Context) error {
86+
if c.String("ztdo") == "" && c.String("ztdo-id") == "" {
87+
return fmt.Errorf("--ztdo or --ztdo-id MUST be specified")
88+
}
89+
if c.String("ztdo") != "" && c.String("ztdo-id") != "" {
90+
return fmt.Errorf("--ztdo and --ztdo-id CANNOT be specified at the same time")
91+
}
92+
return nil
8393
},
8494
Action: func(c *cli.Context) error {
8595
ztdo := c.String("ztdo")
96+
ztdoId := c.String("ztdo-id")
8697
output := c.String("output")
87-
return runDHPApp(ztdo, output)
98+
return runDHPApp(ztdo, ztdoId, output)
8899
},
89100
}
90101

@@ -123,7 +134,8 @@ func runApp() error {
123134
a.Stop()
124135
return nil
125136
}
126-
func runDHPApp(ztdo string, output string) error {
137+
138+
func runDHPApp(ztdo string, ztdoId string, output string) error {
127139
exeFilePath, err := os.Executable()
128140
if err != nil {
129141
return err
@@ -136,9 +148,9 @@ func runDHPApp(ztdo string, output string) error {
136148
if err != nil {
137149
return err
138150
}
139-
if ztdo != "" {
151+
if ztdo != "" || ztdoId != "" {
140152
//request ztdo file
141-
a.StartDecodeZtdo(ztdo, output)
153+
a.StartDecodeZtdo(ztdo, ztdoId, output)
142154
} else {
143155
a.StartKnockLoop()
144156
}

endpoints/agent/udpagent.go

Lines changed: 196 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"net"
8+
"os"
89
"os/exec"
910
"path/filepath"
1011
"sync"
@@ -13,9 +14,11 @@ import (
1314

1415
"github.com/OpenNHP/opennhp/nhp/common"
1516
"github.com/OpenNHP/opennhp/nhp/core"
17+
wasmEngine "github.com/OpenNHP/opennhp/nhp/core/wasm/engine"
18+
ztdolib "github.com/OpenNHP/opennhp/nhp/core/ztdo"
1619
"github.com/OpenNHP/opennhp/nhp/log"
20+
utils "github.com/OpenNHP/opennhp/nhp/utils"
1721
"github.com/OpenNHP/opennhp/nhp/version"
18-
ztdolib "github.com/OpenNHP/opennhp/nhp/core/ztdo"
1922
)
2023

2124
var (
@@ -684,11 +687,29 @@ func (a *UdpAgent) FindServerPeerFromResource(res *KnockResource) *core.UdpPeer
684687
ztdo: Ztdo file path
685688
output: Decrypted file output path
686689
*/
687-
func (a *UdpAgent) StartDecodeZtdo(ztdoPath string, output string) {
690+
func (a *UdpAgent) StartDecodeZtdo(ztdoPath string, ztdoId string, output string) {
691+
var doId string
692+
693+
if output == "" {
694+
// generate temporary file path
695+
var err error
696+
output, err = utils.GenerateTempFilePath("plaintext-*")
697+
if err != nil {
698+
fmt.Println("Error: fail to generating temporary file path:", err)
699+
return
700+
}
701+
}
702+
688703
ztdo := ztdolib.NewZtdo()
689-
if err := ztdo.ParseHeader(ztdoPath); err != nil {
690-
fmt.Println("ParseHeader error:", err)
691-
return
704+
if ztdoPath != "" {
705+
if err := ztdo.ParseHeader(ztdoPath); err != nil {
706+
fmt.Println("Error: parse header error:", err)
707+
return
708+
}
709+
710+
doId = ztdo.GetObjectID()
711+
} else {
712+
doId = ztdoId
692713
}
693714

694715
eccType := core.ECC_SM2
@@ -699,7 +720,6 @@ func (a *UdpAgent) StartDecodeZtdo(ztdoPath string, output string) {
699720
teePrk, _ := base64.StdEncoding.DecodeString(a.config.TEEPrivateKeyBase64)
700721
teeEcdh := core.ECDHFromKey(eccType, teePrk)
701722

702-
doId := ztdo.GetObjectID()
703723
darMsg := common.DARMsg{
704724
DoId: doId,
705725
UserId: a.config.UserId,
@@ -713,12 +733,40 @@ func (a *UdpAgent) StartDecodeZtdo(ztdoPath string, output string) {
713733

714734
if err := json.Unmarshal([]byte(dagMsg.Kao.WrappedDataKey), &dataPrkWrapping); err != nil {
715735
log.Error("failed to unmarshal data private key wrapping: %v\n", err)
716-
fmt.Printf("failed to unmarshal data private key wrapping: %v\n", err)
736+
fmt.Printf("Error: failed to unmarshal data private key wrapping: %v\n", err)
717737
return
718738
}
719739

720740
providerPbk, _ := base64.StdEncoding.DecodeString(dataPrkWrapping.ProviderPublicKeyBase64)
721741

742+
if ztdoPath == "" {
743+
if dagMsg.AccessUrl == "" {
744+
log.Error("access url is empty, please check with data provider")
745+
fmt.Println("Error: access url is empty, please check with data provider")
746+
return
747+
}
748+
749+
var err error
750+
ztdoPath, err = utils.DownloadFileToTemp(dagMsg.AccessUrl, "ztdo-")
751+
defer os.Remove(filepath.Dir(ztdoPath))
752+
defer os.Remove(ztdoPath)
753+
if err != nil {
754+
log.Error("failed to download ztdo: %v\n", err)
755+
fmt.Printf("Error: failed to download ztdo: %v\n", err)
756+
return
757+
}
758+
759+
if err := ztdo.ParseHeader(ztdoPath); err != nil {
760+
fmt.Printf("Error: failed to parse ztdo header:%s\n", err)
761+
return
762+
}
763+
764+
if ztdoId != ztdo.GetObjectID() {
765+
fmt.Printf("Error: ztdo id mismatch, please check with data provider\n")
766+
return
767+
}
768+
}
769+
722770
sa := ztdolib.NewSymmetricAgreement(ztdo.GetECCMode(), false)
723771
sa.SetMessagePatterns(ztdolib.DataPrivateKeyWrappingPatterns)
724772
sa.SetPsk([]byte(ztdolib.InitialDHPKeyWrappingString))
@@ -730,16 +778,21 @@ func (a *UdpAgent) StartDecodeZtdo(ztdoPath string, output string) {
730778

731779
dataPrk, _ := dataPrkWrapping.Unwrap(gcmKey[:], ad)
732780

733-
cmd := exec.Command(a.config.DHPExeCMD, "run", "--mode=decrypt", "--ztdo="+ztdoPath, "--output="+output, "--dataPrivateKey="+dataPrk, "--providerPublicKey="+dataPrkWrapping.ProviderPublicKeyBase64)
781+
if ztdoPath == "" || output == "" {
782+
fmt.Printf("Error: ztdo path or output is empty\n")
783+
return
784+
}
785+
786+
cmd := exec.Command(a.config.DHPExeCMD, "run", "--mode=decrypt", "--ztdo="+ztdoPath, "--output="+output, "--data-private-key="+dataPrk, "--provider-public-key="+dataPrkWrapping.ProviderPublicKeyBase64)
734787

735788
_, err := cmd.CombinedOutput()
736789
if err != nil {
737-
fmt.Println("ZTDO File Decryption: Failure with error: ", err.Error())
790+
fmt.Println("Error: fail to decrypt ztdo file with error: ", err.Error())
738791
} else {
739-
fmt.Println("ZTDO File Decryption: Success")
792+
fmt.Println("Successfully decrypt ztdo file into", output)
740793
}
741794
} else {
742-
fmt.Printf("fail to request ZTDO with error: %s.\n", dagMsg.ErrMsg)
795+
fmt.Printf("Error: fail to request ztdo with error: %s.\n", dagMsg.ErrMsg)
743796
}
744797
}
745798

@@ -781,38 +834,165 @@ func (a *UdpAgent) SendDARMsgToServer(server *core.UdpPeer, msg common.DARMsg) (
781834
serverPpd := <-drgMd.ResponseMsgCh
782835
close(drgMd.ResponseMsgCh)
783836

837+
//Wait for NHP-Server response and implement reception and processing within the func() function below.
838+
var err error
839+
result, dsaMsg := func() (bool, *common.DSAMsg) {
840+
dsaMsg := &common.DSAMsg{}
841+
if serverPpd.Error != nil {
842+
log.Error("Agent(%s#%d)[SendDARMsgToServer] failed to receive response from server %s: %v", drgMsg.DoId, drgMd.TransactionId, server.Ip, serverPpd.Error)
843+
err = serverPpd.Error
844+
return false, dsaMsg
845+
}
846+
847+
if serverPpd.HeaderType != core.NHP_DSA {
848+
log.Error("DB(%s#%d)[SendDARMsgToServer] response from server %s has wrong type: %s", drgMsg.DoId, drgMd.TransactionId, server.Ip, core.HeaderTypeToString(serverPpd.HeaderType))
849+
err = common.ErrTransactionRepliedWithWrongType
850+
return false, dsaMsg
851+
}
852+
//message []byte to DSAMSg Object
853+
err = json.Unmarshal(serverPpd.BodyMessage, dsaMsg)
854+
if err != nil {
855+
log.Error("Agent(%s#%d)[HandleDHPDAGMessage] failed to parse %s message: %v", drgMsg.DoId, serverPpd.SenderTrxId, core.HeaderTypeToString(serverPpd.HeaderType), err)
856+
return false, dsaMsg
857+
}
858+
dsaMsgString, err := json.Marshal(dsaMsg)
859+
if err != nil {
860+
log.Error("Agent(%s#%d)DSAMsg failed to parse %s message: %v", dsaMsg.DoId, err)
861+
return false, dsaMsg
862+
}
863+
log.Info("SendDARMsgToServer response result: %v", dsaMsgString)
864+
if dsaMsg.ErrCode != 0 {
865+
log.Error("SendDARMsgToServer send failed,error:", dsaMsg.ErrMsg)
866+
return false, dsaMsg
867+
}
868+
return true, dsaMsg
869+
}()
870+
871+
if result {
872+
// Collect attestation proofs with smart policy
873+
evidence, err := a.onAttestationCollect(dsaMsg.Spo)
874+
if err != nil {
875+
dagMsg := &common.DAGMsg{}
876+
dagMsg.DoId = dsaMsg.DoId
877+
dagMsg.ErrCode = 1
878+
dagMsg.ErrMsg = err.Error()
879+
880+
return false, dagMsg
881+
}
882+
883+
// avoid flood attack from server side
884+
time.Sleep(core.MinimalRecvIntervalMs * time.Millisecond)
885+
886+
davMsg := common.DAVMsg{
887+
DoId: msg.DoId,
888+
SpoId: dsaMsg.SpoId,
889+
Evidence: evidence,
890+
}
891+
892+
return a.SendDAVMsgToServer(server, davMsg)
893+
} else {
894+
dagMsg := &common.DAGMsg{}
895+
dagMsg.DoId = dsaMsg.DoId
896+
dagMsg.ErrCode = dsaMsg.ErrCode
897+
dagMsg.ErrMsg = dsaMsg.ErrMsg
898+
899+
return result, dagMsg
900+
}
901+
}
902+
903+
func (a *UdpAgent) SendDAVMsgToServer(server *core.UdpPeer, msg common.DAVMsg) (bool, *common.DAGMsg) {
904+
result := false
905+
sendAddr := server.SendAddr()
906+
if sendAddr == nil {
907+
log.Critical("device(%s)[SendDAVMsgToServer] register server IP cannot be parsed", a)
908+
}
909+
davMsg := msg
910+
davBytes, _ := json.Marshal(davMsg)
911+
davMd := &core.MsgData{
912+
RemoteAddr: sendAddr.(*net.UDPAddr),
913+
HeaderType: core.NHP_DAV,
914+
TransactionId: a.device.NextCounterIndex(),
915+
Compress: true,
916+
Message: davBytes,
917+
PeerPk: server.PublicKey(),
918+
ResponseMsgCh: make(chan *core.PacketParserData),
919+
}
920+
921+
currTime := time.Now().UnixNano()
922+
if !a.IsRunning() {
923+
log.Error("server-agentMsgData channel closed or being closed, skip sending")
924+
return result, nil
925+
}
926+
// device will create or find existing connection and sends the MsgAssembler via that connection
927+
a.sendMsgCh <- davMd
928+
server.UpdateSend(currTime)
929+
// block until transaction completes
930+
serverPpd := <-davMd.ResponseMsgCh
931+
close(davMd.ResponseMsgCh)
932+
784933
//Wait for NHP-Server response and implement reception and processing within the func() function below.
785934
var err error
786935
result, dagMsg := func() (bool, *common.DAGMsg) {
787936
dagMsg := &common.DAGMsg{}
788937
if serverPpd.Error != nil {
789-
log.Error("Agent(%s#%d)[SendDARMsgToServer] failed to receive response from server %s: %v", drgMsg.DoId, drgMd.TransactionId, server.Ip, serverPpd.Error)
938+
log.Error("Agent(%s#%d)[SendDAVMsgToServer] failed to receive response from server %s: %v", davMsg.DoId, davMd.TransactionId, server.Ip, serverPpd.Error)
790939
err = serverPpd.Error
791940
return false, dagMsg
792941
}
793942

794943
if serverPpd.HeaderType != core.NHP_DAG {
795-
log.Error("DB(%s#%d)[SendDARMsgToServer] response from server %s has wrong type: %s", drgMsg.DoId, drgMd.TransactionId, server.Ip, core.HeaderTypeToString(serverPpd.HeaderType))
944+
log.Error("DB(%s#%d)[SendDAVMsgToServer] response from server %s has wrong type: %s", davMsg.DoId, davMd.TransactionId, server.Ip, core.HeaderTypeToString(serverPpd.HeaderType))
796945
err = common.ErrTransactionRepliedWithWrongType
797946
return false, dagMsg
798947
}
799948
//message []byte to DAGMSg Object
800949
err = json.Unmarshal(serverPpd.BodyMessage, dagMsg)
801950
if err != nil {
802-
log.Error("Agent(%s#%d)[HandleDHPDAGMessage] failed to parse %s message: %v", drgMsg.DoId, serverPpd.SenderTrxId, core.HeaderTypeToString(serverPpd.HeaderType), err)
951+
log.Error("Agent(%s#%d)[HandleDHPDAVMessage] failed to parse %s message: %v", davMsg.DoId, serverPpd.SenderTrxId, core.HeaderTypeToString(serverPpd.HeaderType), err)
803952
return false, dagMsg
804953
}
805954
dagMsgString, err := json.Marshal(dagMsg)
806955
if err != nil {
807956
log.Error("Agent(%s#%d)DAKMsg failed to parse %s message: %v", dagMsg.DoId, err)
808957
return false, dagMsg
809958
}
810-
log.Info("SendDARMsgToServer response result%v", dagMsgString)
959+
log.Info("SendDAVMsgToServer response result: %v", dagMsgString)
811960
if dagMsg.ErrCode != 0 {
812-
log.Error("SendDARMsgToServer send failed,error:", dagMsg.ErrMsg)
961+
log.Error("SendDAVMsgToServer send failed,error:", dagMsg.ErrMsg)
813962
return false, dagMsg
814963
}
815964
return true, dagMsg
816965
}()
817966
return result, dagMsg
818967
}
968+
969+
func (s *UdpAgent) onAttestationCollect(spo *common.SmartPolicy) (string, error) {
970+
if spo.Policy == "" {
971+
return "", nil
972+
}
973+
974+
wasmBytes, err := base64.StdEncoding.DecodeString(spo.Policy)
975+
if err != nil {
976+
wasmPath, err := utils.DownloadFileToTemp(spo.Policy, "wasm-")
977+
defer os.Remove(filepath.Dir(wasmPath))
978+
defer os.Remove(wasmPath)
979+
if err != nil {
980+
return "", err
981+
}
982+
wasmBytes, err = os.ReadFile(wasmPath)
983+
if err != nil {
984+
return "", err
985+
}
986+
}
987+
988+
engine := wasmEngine.NewEngine()
989+
err = engine.LoadWasm(wasmBytes)
990+
defer engine.Close()
991+
if err != nil {
992+
return "", err
993+
}
994+
995+
attestation := engine.OnAttestationCollect()
996+
997+
return attestation, nil
998+
}

endpoints/db/config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
var (
1616
baseConfigWatch io.Closer
1717
serverConfigWatch io.Closer
18-
teesConfigWatch io.Closer
18+
teesConfigWatch io.Closer
1919
resourceConfigWatch io.Closer
2020

2121
errLoadConfig = fmt.Errorf("config load error")
@@ -24,7 +24,7 @@ var (
2424
type Config struct {
2525
LogLevel int
2626
PrivateKeyBase64 string
27-
DefaultCipherScheme int `json:"defaultCipherScheme"`
27+
DefaultCipherScheme int `json:"defaultCipherScheme"`
2828
SymmetricCipherMode string `json:"symmetricCipherMode"`
2929
DbId string `json:"dbId"`
3030
}
@@ -178,7 +178,7 @@ func (a *UdpDevice) updateTEEConfig(file string) (err error) {
178178
}
179179

180180
teeMap := make(map[string]*TEE)
181-
for _, tee:= range tees.TEEs {
181+
for _, tee := range tees.TEEs {
182182
teeMap[tee.TEEPublicKeyBase64] = tee
183183
}
184184

0 commit comments

Comments
 (0)