s3_sse_test_utils_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package s3api
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "encoding/base64"
  6. "io"
  7. "net/http"
  8. "net/http/httptest"
  9. "testing"
  10. "github.com/gorilla/mux"
  11. "github.com/seaweedfs/seaweedfs/weed/kms"
  12. "github.com/seaweedfs/seaweedfs/weed/kms/local"
  13. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  14. )
  15. // TestKeyPair represents a test SSE-C key pair
  16. type TestKeyPair struct {
  17. Key []byte
  18. KeyB64 string
  19. KeyMD5 string
  20. }
  21. // TestSSEKMSKey represents a test SSE-KMS key
  22. type TestSSEKMSKey struct {
  23. KeyID string
  24. Cleanup func()
  25. }
  26. // GenerateTestSSECKey creates a test SSE-C key pair
  27. func GenerateTestSSECKey(seed byte) *TestKeyPair {
  28. key := make([]byte, 32) // 256-bit key
  29. for i := range key {
  30. key[i] = seed + byte(i)
  31. }
  32. keyB64 := base64.StdEncoding.EncodeToString(key)
  33. md5sum := md5.Sum(key)
  34. keyMD5 := base64.StdEncoding.EncodeToString(md5sum[:])
  35. return &TestKeyPair{
  36. Key: key,
  37. KeyB64: keyB64,
  38. KeyMD5: keyMD5,
  39. }
  40. }
  41. // SetupTestSSECHeaders sets SSE-C headers on an HTTP request
  42. func SetupTestSSECHeaders(req *http.Request, keyPair *TestKeyPair) {
  43. req.Header.Set(s3_constants.AmzServerSideEncryptionCustomerAlgorithm, "AES256")
  44. req.Header.Set(s3_constants.AmzServerSideEncryptionCustomerKey, keyPair.KeyB64)
  45. req.Header.Set(s3_constants.AmzServerSideEncryptionCustomerKeyMD5, keyPair.KeyMD5)
  46. }
  47. // SetupTestSSECCopyHeaders sets SSE-C copy source headers on an HTTP request
  48. func SetupTestSSECCopyHeaders(req *http.Request, keyPair *TestKeyPair) {
  49. req.Header.Set(s3_constants.AmzCopySourceServerSideEncryptionCustomerAlgorithm, "AES256")
  50. req.Header.Set(s3_constants.AmzCopySourceServerSideEncryptionCustomerKey, keyPair.KeyB64)
  51. req.Header.Set(s3_constants.AmzCopySourceServerSideEncryptionCustomerKeyMD5, keyPair.KeyMD5)
  52. }
  53. // SetupTestKMS initializes a local KMS provider for testing
  54. func SetupTestKMS(t *testing.T) *TestSSEKMSKey {
  55. // Initialize local KMS provider directly
  56. provider, err := local.NewLocalKMSProvider(nil)
  57. if err != nil {
  58. t.Fatalf("Failed to create local KMS provider: %v", err)
  59. }
  60. // Set it as the global provider
  61. kms.SetGlobalKMSProvider(provider)
  62. // Create a test key
  63. localProvider := provider.(*local.LocalKMSProvider)
  64. testKey, err := localProvider.CreateKey("Test key for SSE-KMS", []string{"test-key"})
  65. if err != nil {
  66. t.Fatalf("Failed to create test key: %v", err)
  67. }
  68. // Cleanup function
  69. cleanup := func() {
  70. kms.SetGlobalKMSProvider(nil) // Clear global KMS
  71. if err := provider.Close(); err != nil {
  72. t.Logf("Warning: Failed to close KMS provider: %v", err)
  73. }
  74. }
  75. return &TestSSEKMSKey{
  76. KeyID: testKey.KeyID,
  77. Cleanup: cleanup,
  78. }
  79. }
  80. // SetupTestSSEKMSHeaders sets SSE-KMS headers on an HTTP request
  81. func SetupTestSSEKMSHeaders(req *http.Request, keyID string) {
  82. req.Header.Set(s3_constants.AmzServerSideEncryption, "aws:kms")
  83. if keyID != "" {
  84. req.Header.Set(s3_constants.AmzServerSideEncryptionAwsKmsKeyId, keyID)
  85. }
  86. }
  87. // CreateTestMetadata creates test metadata with SSE information
  88. func CreateTestMetadata() map[string][]byte {
  89. return make(map[string][]byte)
  90. }
  91. // CreateTestMetadataWithSSEC creates test metadata containing SSE-C information
  92. func CreateTestMetadataWithSSEC(keyPair *TestKeyPair) map[string][]byte {
  93. metadata := CreateTestMetadata()
  94. metadata[s3_constants.AmzServerSideEncryptionCustomerAlgorithm] = []byte("AES256")
  95. metadata[s3_constants.AmzServerSideEncryptionCustomerKeyMD5] = []byte(keyPair.KeyMD5)
  96. // Add encryption IV and other encrypted data that would be stored
  97. iv := make([]byte, 16)
  98. for i := range iv {
  99. iv[i] = byte(i)
  100. }
  101. StoreIVInMetadata(metadata, iv)
  102. return metadata
  103. }
  104. // CreateTestMetadataWithSSEKMS creates test metadata containing SSE-KMS information
  105. func CreateTestMetadataWithSSEKMS(sseKey *SSEKMSKey) map[string][]byte {
  106. metadata := CreateTestMetadata()
  107. metadata[s3_constants.AmzServerSideEncryption] = []byte("aws:kms")
  108. if sseKey != nil {
  109. serialized, _ := SerializeSSEKMSMetadata(sseKey)
  110. metadata[s3_constants.AmzEncryptedDataKey] = sseKey.EncryptedDataKey
  111. metadata[s3_constants.AmzEncryptionContextMeta] = serialized
  112. }
  113. return metadata
  114. }
  115. // CreateTestHTTPRequest creates a test HTTP request with optional SSE headers
  116. func CreateTestHTTPRequest(method, path string, body []byte) *http.Request {
  117. var bodyReader io.Reader
  118. if body != nil {
  119. bodyReader = bytes.NewReader(body)
  120. }
  121. req := httptest.NewRequest(method, path, bodyReader)
  122. return req
  123. }
  124. // CreateTestHTTPResponse creates a test HTTP response recorder
  125. func CreateTestHTTPResponse() *httptest.ResponseRecorder {
  126. return httptest.NewRecorder()
  127. }
  128. // SetupTestMuxVars sets up mux variables for testing
  129. func SetupTestMuxVars(req *http.Request, vars map[string]string) {
  130. mux.SetURLVars(req, vars)
  131. }
  132. // AssertSSECHeaders verifies that SSE-C response headers are set correctly
  133. func AssertSSECHeaders(t *testing.T, w *httptest.ResponseRecorder, keyPair *TestKeyPair) {
  134. algorithm := w.Header().Get(s3_constants.AmzServerSideEncryptionCustomerAlgorithm)
  135. if algorithm != "AES256" {
  136. t.Errorf("Expected algorithm AES256, got %s", algorithm)
  137. }
  138. keyMD5 := w.Header().Get(s3_constants.AmzServerSideEncryptionCustomerKeyMD5)
  139. if keyMD5 != keyPair.KeyMD5 {
  140. t.Errorf("Expected key MD5 %s, got %s", keyPair.KeyMD5, keyMD5)
  141. }
  142. }
  143. // AssertSSEKMSHeaders verifies that SSE-KMS response headers are set correctly
  144. func AssertSSEKMSHeaders(t *testing.T, w *httptest.ResponseRecorder, keyID string) {
  145. algorithm := w.Header().Get(s3_constants.AmzServerSideEncryption)
  146. if algorithm != "aws:kms" {
  147. t.Errorf("Expected algorithm aws:kms, got %s", algorithm)
  148. }
  149. if keyID != "" {
  150. responseKeyID := w.Header().Get(s3_constants.AmzServerSideEncryptionAwsKmsKeyId)
  151. if responseKeyID != keyID {
  152. t.Errorf("Expected key ID %s, got %s", keyID, responseKeyID)
  153. }
  154. }
  155. }
  156. // CreateCorruptedSSECMetadata creates intentionally corrupted SSE-C metadata for testing
  157. func CreateCorruptedSSECMetadata() map[string][]byte {
  158. metadata := CreateTestMetadata()
  159. // Missing algorithm
  160. metadata[s3_constants.AmzServerSideEncryptionCustomerKeyMD5] = []byte("invalid-md5")
  161. return metadata
  162. }
  163. // CreateCorruptedSSEKMSMetadata creates intentionally corrupted SSE-KMS metadata for testing
  164. func CreateCorruptedSSEKMSMetadata() map[string][]byte {
  165. metadata := CreateTestMetadata()
  166. metadata[s3_constants.AmzServerSideEncryption] = []byte("aws:kms")
  167. // Invalid encrypted data key
  168. metadata[s3_constants.AmzEncryptedDataKey] = []byte("invalid-base64!")
  169. return metadata
  170. }
  171. // TestDataSizes provides various data sizes for testing
  172. var TestDataSizes = []int{
  173. 0, // Empty
  174. 1, // Single byte
  175. 15, // Less than AES block size
  176. 16, // Exactly AES block size
  177. 17, // More than AES block size
  178. 1024, // 1KB
  179. 65536, // 64KB
  180. 1048576, // 1MB
  181. }
  182. // GenerateTestData creates test data of specified size
  183. func GenerateTestData(size int) []byte {
  184. data := make([]byte, size)
  185. for i := range data {
  186. data[i] = byte(i % 256)
  187. }
  188. return data
  189. }