signature_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package signature
  2. import (
  3. _ "embed"
  4. "os"
  5. "path/filepath"
  6. "testing"
  7. "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
  8. )
  9. //go:embed testdata/dummy_plugin.difypkg
  10. var dummyPlugin []byte
  11. func TestGenerateKeyPair(t *testing.T) {
  12. // create a temporary directory for testing
  13. tempDir := t.TempDir()
  14. // create a key pair
  15. keyPairName := filepath.Join(tempDir, "test_key_pair")
  16. GenerateKeyPair(keyPairName)
  17. privateKeyPath := keyPairName + ".private.pem"
  18. publicKeyPath := keyPairName + ".public.pem"
  19. // check if the key files are created
  20. if _, err := os.Stat(privateKeyPath); os.IsNotExist(err) {
  21. t.Errorf("Private key file was not created: %s", privateKeyPath)
  22. }
  23. if _, err := os.Stat(publicKeyPath); os.IsNotExist(err) {
  24. t.Errorf("Public key file was not created: %s", publicKeyPath)
  25. }
  26. // check if the key files can be loaded
  27. privateKeyBytes, err := os.ReadFile(privateKeyPath)
  28. if err != nil {
  29. t.Fatalf("Failed to read private key file: %v", err)
  30. }
  31. publicKeyBytes, err := os.ReadFile(publicKeyPath)
  32. if err != nil {
  33. t.Fatalf("Failed to read public key file: %v", err)
  34. }
  35. // check if the keys can be loaded
  36. _, err = encryption.LoadPrivateKey(privateKeyBytes)
  37. if err != nil {
  38. t.Errorf("Failed to load private key: %v", err)
  39. }
  40. _, err = encryption.LoadPublicKey(publicKeyBytes)
  41. if err != nil {
  42. t.Errorf("Failed to load public key: %v", err)
  43. }
  44. }
  45. func TestSignAndVerify(t *testing.T) {
  46. // create a temporary directory for testing
  47. tempDir := t.TempDir()
  48. // extract the minimal plugin content from the embedded data to a file
  49. dummyPluginPath := filepath.Join(tempDir, "dummy_plugin.difypkg")
  50. if err := os.WriteFile(dummyPluginPath, dummyPlugin, 0644); err != nil {
  51. t.Fatalf("Failed to create dummy plugin file: %v", err)
  52. }
  53. // create two key pairs
  54. keyPair1Name := filepath.Join(tempDir, "test_key_pair_1")
  55. keyPair2Name := filepath.Join(tempDir, "test_key_pair_2")
  56. GenerateKeyPair(keyPair1Name)
  57. GenerateKeyPair(keyPair2Name)
  58. privateKey1Path := keyPair1Name + ".private.pem"
  59. publicKey1Path := keyPair1Name + ".public.pem"
  60. privateKey2Path := keyPair2Name + ".private.pem"
  61. publicKey2Path := keyPair2Name + ".public.pem"
  62. // test case definition for table-driven tests
  63. type testCase struct {
  64. name string
  65. signKeyPath string
  66. verifyKeyPath string
  67. expectSuccess bool
  68. }
  69. // test cases
  70. tests := []testCase{
  71. {
  72. name: "sign with keypair1, verify with keypair1",
  73. signKeyPath: privateKey1Path,
  74. verifyKeyPath: publicKey1Path,
  75. expectSuccess: true,
  76. },
  77. {
  78. name: "sign with keypair1, verify with keypair2",
  79. signKeyPath: privateKey1Path,
  80. verifyKeyPath: publicKey2Path,
  81. expectSuccess: false,
  82. },
  83. {
  84. name: "sign with keypair2, verify with keypair2",
  85. signKeyPath: privateKey2Path,
  86. verifyKeyPath: publicKey2Path,
  87. expectSuccess: true,
  88. },
  89. {
  90. name: "sign with keypair2, verify with keypair1",
  91. signKeyPath: privateKey2Path,
  92. verifyKeyPath: publicKey1Path,
  93. expectSuccess: false,
  94. },
  95. {
  96. name: "sign with keypair1, verify without key",
  97. signKeyPath: privateKey1Path,
  98. verifyKeyPath: "",
  99. expectSuccess: false,
  100. },
  101. {
  102. name: "sign with keypair2, verify without key",
  103. signKeyPath: privateKey2Path,
  104. verifyKeyPath: "",
  105. expectSuccess: false,
  106. },
  107. }
  108. // execute each test case
  109. for _, tt := range tests {
  110. t.Run(tt.name, func(t *testing.T) {
  111. // create a temporary file for each test case
  112. testPluginPath := filepath.Join(tempDir, "test_plugin_"+tt.name+".difypkg")
  113. if err := os.WriteFile(testPluginPath, dummyPlugin, 0644); err != nil {
  114. t.Fatalf("Failed to create test plugin file: %v", err)
  115. }
  116. // sign the plugin
  117. Sign(testPluginPath, tt.signKeyPath)
  118. // get the path of the signed plugin
  119. dir := filepath.Dir(testPluginPath)
  120. base := filepath.Base(testPluginPath)
  121. ext := filepath.Ext(base)
  122. name := base[:len(base)-len(ext)]
  123. dummyPluginPath := filepath.Join(dir, name+".signed"+ext)
  124. // check if the signed plugin file was created
  125. if _, err := os.Stat(dummyPluginPath); os.IsNotExist(err) {
  126. t.Fatalf("Signed plugin file was not created: %s", dummyPluginPath)
  127. }
  128. // verify the signed plugin and check the result
  129. err := Verify(dummyPluginPath, tt.verifyKeyPath)
  130. if tt.expectSuccess && err != nil {
  131. t.Errorf("Expected verification to succeed, but got error: %v", err)
  132. } else if !tt.expectSuccess && err == nil {
  133. t.Errorf("Expected verification to fail, but it succeeded")
  134. }
  135. })
  136. }
  137. }
  138. // TestVerifyUnsigned tests verification of an unsigned difypkg file
  139. func TestVerifyUnsigned(t *testing.T) {
  140. // create a temporary directory for testing
  141. tempDir := t.TempDir()
  142. // extract the minimal plugin content from the embedded data to a file
  143. dummyPluginPath := filepath.Join(tempDir, "dummy_plugin.difypkg")
  144. if err := os.WriteFile(dummyPluginPath, dummyPlugin, 0644); err != nil {
  145. t.Fatalf("Failed to create dummy plugin file: %v", err)
  146. }
  147. // create a key pair
  148. keyPairName := filepath.Join(tempDir, "test_key_pair")
  149. GenerateKeyPair(keyPairName)
  150. publicKeyPath := keyPairName + ".public.pem"
  151. // Try to verify the unsigned plugin file
  152. err := Verify(dummyPluginPath, publicKeyPath)
  153. if err == nil {
  154. t.Errorf("Expected verification of unsigned file to fail, but it succeeded")
  155. }
  156. }
  157. // TestVerifyTampered tests verification of a tampered signed difypkg file
  158. func TestVerifyTampered(t *testing.T) {
  159. // create a temporary directory for testing
  160. tempDir := t.TempDir()
  161. // extract the minimal plugin content from the embedded data to a file
  162. dummyPluginPath := filepath.Join(tempDir, "dummy_plugin.difypkg")
  163. if err := os.WriteFile(dummyPluginPath, dummyPlugin, 0644); err != nil {
  164. t.Fatalf("Failed to create dummy plugin file: %v", err)
  165. }
  166. // create a key pair
  167. keyPairName := filepath.Join(tempDir, "test_key_pair")
  168. GenerateKeyPair(keyPairName)
  169. privateKeyPath := keyPairName + ".private.pem"
  170. publicKeyPath := keyPairName + ".public.pem"
  171. // Sign the plugin
  172. Sign(dummyPluginPath, privateKeyPath)
  173. // Get the path of the signed plugin
  174. dir := filepath.Dir(dummyPluginPath)
  175. base := filepath.Base(dummyPluginPath)
  176. ext := filepath.Ext(base)
  177. name := base[:len(base)-len(ext)]
  178. signedDummyPluginPath := filepath.Join(dir, name+".signed"+ext)
  179. // Read the signed plugin
  180. signedPluginData, err := os.ReadFile(signedDummyPluginPath)
  181. if err != nil {
  182. t.Fatalf("Failed to read signed plugin file: %v", err)
  183. }
  184. // tamper the signed plugin data
  185. signedPluginData[len(signedPluginData)-10] = 0
  186. // write the tampered data back to the file
  187. tamperedPluginPath := filepath.Join(tempDir, "tampered_plugin.signed.difypkg")
  188. if err := os.WriteFile(tamperedPluginPath, signedPluginData, 0644); err != nil {
  189. t.Fatalf("Failed to write tampered plugin file: %v", err)
  190. }
  191. // try to verify the tampered plugin file
  192. err = Verify(tamperedPluginPath, publicKeyPath)
  193. if err == nil {
  194. t.Errorf("Expected verification of tampered file to fail, but it succeeded")
  195. }
  196. }