s3api_put_handlers.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package s3api
  2. import (
  3. "encoding/base64"
  4. "io"
  5. "net/http"
  6. "strings"
  7. "github.com/seaweedfs/seaweedfs/weed/glog"
  8. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  9. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  10. )
  11. // PutToFilerEncryptionResult holds the result of encryption processing
  12. type PutToFilerEncryptionResult struct {
  13. DataReader io.Reader
  14. SSEType string
  15. CustomerKey *SSECustomerKey
  16. SSEIV []byte
  17. SSEKMSKey *SSEKMSKey
  18. SSES3Key *SSES3Key
  19. SSEKMSMetadata []byte
  20. SSES3Metadata []byte
  21. }
  22. // calculatePartOffset calculates unique offset for each part to prevent IV reuse in multipart uploads
  23. // AWS S3 part numbers must start from 1, never 0 or negative
  24. func calculatePartOffset(partNumber int) int64 {
  25. // AWS S3 part numbers must start from 1, never 0 or negative
  26. if partNumber < 1 {
  27. glog.Errorf("Invalid partNumber: %d. Must be >= 1.", partNumber)
  28. return 0
  29. }
  30. // Using a large multiplier to ensure block offsets for different parts do not overlap.
  31. // S3 part size limit is 5GB, so this provides a large safety margin.
  32. partOffset := int64(partNumber-1) * s3_constants.PartOffsetMultiplier
  33. return partOffset
  34. }
  35. // handleSSECEncryption processes SSE-C encryption for the data reader
  36. func (s3a *S3ApiServer) handleSSECEncryption(r *http.Request, dataReader io.Reader) (io.Reader, *SSECustomerKey, []byte, s3err.ErrorCode) {
  37. // Handle SSE-C encryption if requested
  38. customerKey, err := ParseSSECHeaders(r)
  39. if err != nil {
  40. glog.Errorf("SSE-C header validation failed: %v", err)
  41. // Use shared error mapping helper
  42. errCode := MapSSECErrorToS3Error(err)
  43. return nil, nil, nil, errCode
  44. }
  45. // Apply SSE-C encryption if customer key is provided
  46. var sseIV []byte
  47. if customerKey != nil {
  48. encryptedReader, iv, encErr := CreateSSECEncryptedReader(dataReader, customerKey)
  49. if encErr != nil {
  50. return nil, nil, nil, s3err.ErrInternalError
  51. }
  52. dataReader = encryptedReader
  53. sseIV = iv
  54. }
  55. return dataReader, customerKey, sseIV, s3err.ErrNone
  56. }
  57. // handleSSEKMSEncryption processes SSE-KMS encryption for the data reader
  58. func (s3a *S3ApiServer) handleSSEKMSEncryption(r *http.Request, dataReader io.Reader, partOffset int64) (io.Reader, *SSEKMSKey, []byte, s3err.ErrorCode) {
  59. // Handle SSE-KMS encryption if requested
  60. if !IsSSEKMSRequest(r) {
  61. return dataReader, nil, nil, s3err.ErrNone
  62. }
  63. glog.V(3).Infof("handleSSEKMSEncryption: SSE-KMS request detected, processing encryption")
  64. // Parse SSE-KMS headers
  65. keyID := r.Header.Get(s3_constants.AmzServerSideEncryptionAwsKmsKeyId)
  66. bucketKeyEnabled := strings.ToLower(r.Header.Get(s3_constants.AmzServerSideEncryptionBucketKeyEnabled)) == "true"
  67. // Build encryption context
  68. bucket, object := s3_constants.GetBucketAndObject(r)
  69. encryptionContext := BuildEncryptionContext(bucket, object, bucketKeyEnabled)
  70. // Add any user-provided encryption context
  71. if contextHeader := r.Header.Get(s3_constants.AmzServerSideEncryptionContext); contextHeader != "" {
  72. userContext, err := parseEncryptionContext(contextHeader)
  73. if err != nil {
  74. return nil, nil, nil, s3err.ErrInvalidRequest
  75. }
  76. // Merge user context with default context
  77. for k, v := range userContext {
  78. encryptionContext[k] = v
  79. }
  80. }
  81. // Check if a base IV is provided (for multipart uploads)
  82. var encryptedReader io.Reader
  83. var sseKey *SSEKMSKey
  84. var encErr error
  85. baseIVHeader := r.Header.Get(s3_constants.SeaweedFSSSEKMSBaseIVHeader)
  86. if baseIVHeader != "" {
  87. // Decode the base IV from the header
  88. baseIV, decodeErr := base64.StdEncoding.DecodeString(baseIVHeader)
  89. if decodeErr != nil || len(baseIV) != 16 {
  90. return nil, nil, nil, s3err.ErrInternalError
  91. }
  92. // Use the provided base IV with unique part offset for multipart upload consistency
  93. encryptedReader, sseKey, encErr = CreateSSEKMSEncryptedReaderWithBaseIVAndOffset(dataReader, keyID, encryptionContext, bucketKeyEnabled, baseIV, partOffset)
  94. glog.V(4).Infof("Using provided base IV %x for SSE-KMS encryption", baseIV[:8])
  95. } else {
  96. // Generate a new IV for single-part uploads
  97. encryptedReader, sseKey, encErr = CreateSSEKMSEncryptedReaderWithBucketKey(dataReader, keyID, encryptionContext, bucketKeyEnabled)
  98. }
  99. if encErr != nil {
  100. return nil, nil, nil, s3err.ErrInternalError
  101. }
  102. // Prepare SSE-KMS metadata for later header setting
  103. sseKMSMetadata, metaErr := SerializeSSEKMSMetadata(sseKey)
  104. if metaErr != nil {
  105. return nil, nil, nil, s3err.ErrInternalError
  106. }
  107. return encryptedReader, sseKey, sseKMSMetadata, s3err.ErrNone
  108. }
  109. // handleSSES3MultipartEncryption handles multipart upload logic for SSE-S3 encryption
  110. func (s3a *S3ApiServer) handleSSES3MultipartEncryption(r *http.Request, dataReader io.Reader, partOffset int64) (io.Reader, *SSES3Key, s3err.ErrorCode) {
  111. keyDataHeader := r.Header.Get(s3_constants.SeaweedFSSSES3KeyDataHeader)
  112. baseIVHeader := r.Header.Get(s3_constants.SeaweedFSSSES3BaseIVHeader)
  113. glog.V(4).Infof("handleSSES3MultipartEncryption: using provided key and base IV for multipart part")
  114. // Decode the key data
  115. keyData, decodeErr := base64.StdEncoding.DecodeString(keyDataHeader)
  116. if decodeErr != nil {
  117. return nil, nil, s3err.ErrInternalError
  118. }
  119. // Deserialize the SSE-S3 key
  120. keyManager := GetSSES3KeyManager()
  121. key, deserializeErr := DeserializeSSES3Metadata(keyData, keyManager)
  122. if deserializeErr != nil {
  123. return nil, nil, s3err.ErrInternalError
  124. }
  125. // Decode the base IV
  126. baseIV, decodeErr := base64.StdEncoding.DecodeString(baseIVHeader)
  127. if decodeErr != nil || len(baseIV) != s3_constants.AESBlockSize {
  128. return nil, nil, s3err.ErrInternalError
  129. }
  130. // Use the provided base IV with unique part offset for multipart upload consistency
  131. encryptedReader, _, encErr := CreateSSES3EncryptedReaderWithBaseIV(dataReader, key, baseIV, partOffset)
  132. if encErr != nil {
  133. return nil, nil, s3err.ErrInternalError
  134. }
  135. glog.V(4).Infof("handleSSES3MultipartEncryption: using provided base IV %x", baseIV[:8])
  136. return encryptedReader, key, s3err.ErrNone
  137. }
  138. // handleSSES3SinglePartEncryption handles single-part upload logic for SSE-S3 encryption
  139. func (s3a *S3ApiServer) handleSSES3SinglePartEncryption(dataReader io.Reader) (io.Reader, *SSES3Key, s3err.ErrorCode) {
  140. glog.V(4).Infof("handleSSES3SinglePartEncryption: generating new key for single-part upload")
  141. keyManager := GetSSES3KeyManager()
  142. key, err := keyManager.GetOrCreateKey("")
  143. if err != nil {
  144. return nil, nil, s3err.ErrInternalError
  145. }
  146. // Create encrypted reader
  147. encryptedReader, iv, encErr := CreateSSES3EncryptedReader(dataReader, key)
  148. if encErr != nil {
  149. return nil, nil, s3err.ErrInternalError
  150. }
  151. // Store IV on the key object for later decryption
  152. key.IV = iv
  153. // Store the key for later use
  154. keyManager.StoreKey(key)
  155. return encryptedReader, key, s3err.ErrNone
  156. }
  157. // handleSSES3Encryption processes SSE-S3 encryption for the data reader
  158. func (s3a *S3ApiServer) handleSSES3Encryption(r *http.Request, dataReader io.Reader, partOffset int64) (io.Reader, *SSES3Key, []byte, s3err.ErrorCode) {
  159. if !IsSSES3RequestInternal(r) {
  160. return dataReader, nil, nil, s3err.ErrNone
  161. }
  162. glog.V(3).Infof("handleSSES3Encryption: SSE-S3 request detected, processing encryption")
  163. var encryptedReader io.Reader
  164. var sseS3Key *SSES3Key
  165. var errCode s3err.ErrorCode
  166. // Check if this is multipart upload (key data and base IV provided)
  167. keyDataHeader := r.Header.Get(s3_constants.SeaweedFSSSES3KeyDataHeader)
  168. baseIVHeader := r.Header.Get(s3_constants.SeaweedFSSSES3BaseIVHeader)
  169. if keyDataHeader != "" && baseIVHeader != "" {
  170. // Multipart upload: use provided key and base IV
  171. encryptedReader, sseS3Key, errCode = s3a.handleSSES3MultipartEncryption(r, dataReader, partOffset)
  172. } else {
  173. // Single-part upload: generate new key and IV
  174. encryptedReader, sseS3Key, errCode = s3a.handleSSES3SinglePartEncryption(dataReader)
  175. }
  176. if errCode != s3err.ErrNone {
  177. return nil, nil, nil, errCode
  178. }
  179. // Prepare SSE-S3 metadata for later header setting
  180. sseS3Metadata, metaErr := SerializeSSES3Metadata(sseS3Key)
  181. if metaErr != nil {
  182. return nil, nil, nil, s3err.ErrInternalError
  183. }
  184. glog.V(3).Infof("handleSSES3Encryption: prepared SSE-S3 metadata for object")
  185. return encryptedReader, sseS3Key, sseS3Metadata, s3err.ErrNone
  186. }
  187. // handleAllSSEEncryption processes all SSE types in sequence and returns the final encrypted reader
  188. // This eliminates repetitive dataReader assignments and centralizes SSE processing
  189. func (s3a *S3ApiServer) handleAllSSEEncryption(r *http.Request, dataReader io.Reader, partOffset int64) (*PutToFilerEncryptionResult, s3err.ErrorCode) {
  190. result := &PutToFilerEncryptionResult{
  191. DataReader: dataReader,
  192. }
  193. // Handle SSE-C encryption first
  194. encryptedReader, customerKey, sseIV, errCode := s3a.handleSSECEncryption(r, result.DataReader)
  195. if errCode != s3err.ErrNone {
  196. return nil, errCode
  197. }
  198. result.DataReader = encryptedReader
  199. result.CustomerKey = customerKey
  200. result.SSEIV = sseIV
  201. // Handle SSE-KMS encryption
  202. encryptedReader, sseKMSKey, sseKMSMetadata, errCode := s3a.handleSSEKMSEncryption(r, result.DataReader, partOffset)
  203. if errCode != s3err.ErrNone {
  204. return nil, errCode
  205. }
  206. result.DataReader = encryptedReader
  207. result.SSEKMSKey = sseKMSKey
  208. result.SSEKMSMetadata = sseKMSMetadata
  209. // Handle SSE-S3 encryption
  210. encryptedReader, sseS3Key, sseS3Metadata, errCode := s3a.handleSSES3Encryption(r, result.DataReader, partOffset)
  211. if errCode != s3err.ErrNone {
  212. return nil, errCode
  213. }
  214. result.DataReader = encryptedReader
  215. result.SSES3Key = sseS3Key
  216. result.SSES3Metadata = sseS3Metadata
  217. // Set SSE type for response headers
  218. if customerKey != nil {
  219. result.SSEType = s3_constants.SSETypeC
  220. } else if sseKMSKey != nil {
  221. result.SSEType = s3_constants.SSETypeKMS
  222. } else if sseS3Key != nil {
  223. result.SSEType = s3_constants.SSETypeS3
  224. }
  225. return result, s3err.ErrNone
  226. }