From 525c04fd07aca348a96bf49185949bf001a56304 Mon Sep 17 00:00:00 2001 From: Andreas Auernhammer Date: Thu, 9 Aug 2018 22:02:57 +0200 Subject: [PATCH] crypto: add SSE-KMS HTTP header detection (#6228) This commit adds support for detecting SSE-KMS headers. The server should be able to detect SSE-KMS headers to at least fail such S3 requests with not implemented. --- cmd/crypto/header.go | 48 +++++++++++++++++++++++++++++++++++---- cmd/crypto/header_test.go | 43 +++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/cmd/crypto/header.go b/cmd/crypto/header.go index 4bdec840a..0c82cd727 100644 --- a/cmd/crypto/header.go +++ b/cmd/crypto/header.go @@ -19,11 +19,22 @@ import ( "crypto/md5" "encoding/base64" "net/http" + "strings" ) // SSEHeader is the general AWS SSE HTTP header key. const SSEHeader = "X-Amz-Server-Side-Encryption" +const ( + // SSEKmsID is the HTTP header key referencing the SSE-KMS + // key ID. + SSEKmsID = SSEHeader + "-Aws-Kms-Key-Id" + + // SSEKmsContext is the HTTP header key referencing the + // SSE-KMS encryption context. + SSEKmsContext = SSEHeader + "-Context" +) + const ( // SSECAlgorithm is the HTTP header key referencing // the SSE-C algorithm. @@ -52,10 +63,16 @@ const ( SSECopyKeyMD5 = "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5" ) -// SSEAlgorithmAES256 is the only supported value for the SSE-S3 or SSE-C algorithm header. -// For SSE-S3 see: https://docs.aws.amazon.com/AmazonS3/latest/dev/SSEUsingRESTAPI.html -// For SSE-C see: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html -const SSEAlgorithmAES256 = "AES256" +const ( + // SSEAlgorithmAES256 is the only supported value for the SSE-S3 or SSE-C algorithm header. + // For SSE-S3 see: https://docs.aws.amazon.com/AmazonS3/latest/dev/SSEUsingRESTAPI.html + // For SSE-C see: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html + SSEAlgorithmAES256 = "AES256" + + // SSEAlgorithmKMS is the value of 'X-Amz-Server-Side-Encryption' for SSE-KMS. + // See: https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html + SSEAlgorithmKMS = "aws:kms" +) // S3 represents AWS SSE-S3. It provides functionality to handle // SSE-S3 requests. @@ -67,7 +84,7 @@ type s3 struct{} // the S3 client requests SSE-S3. func (s3) IsRequested(h http.Header) bool { _, ok := h[SSEHeader] - return ok + return ok && strings.ToLower(h.Get(SSEHeader)) != SSEAlgorithmKMS // Return only true if the SSE header is specified and does not contain the SSE-KMS value } // ParseHTTP parses the SSE-S3 related HTTP headers and checks @@ -79,6 +96,27 @@ func (s3) ParseHTTP(h http.Header) (err error) { return } +// S3KMS represents AWS SSE-KMS. It provides functionality to +// handle SSE-KMS requests. +var S3KMS = s3KMS{} + +type s3KMS struct{} + +// IsRequested returns true if the HTTP headers indicates that +// the S3 client requests SSE-KMS. +func (s3KMS) IsRequested(h http.Header) bool { + if _, ok := h[SSEKmsID]; ok { + return true + } + if _, ok := h[SSEKmsContext]; ok { + return true + } + if _, ok := h[SSEHeader]; ok { + return strings.ToUpper(h.Get(SSEHeader)) != SSEAlgorithmAES256 // Return only true if the SSE header is specified and does not contain the SSE-S3 value + } + return false +} + var ( // SSEC represents AWS SSE-C. It provides functionality to handle // SSE-C requests. diff --git a/cmd/crypto/header_test.go b/cmd/crypto/header_test.go index eb6fae313..a35142493 100644 --- a/cmd/crypto/header_test.go +++ b/cmd/crypto/header_test.go @@ -19,14 +19,49 @@ import ( "testing" ) +var kmsIsRequestedTests = []struct { + Header http.Header + Expected bool +}{ + {Header: http.Header{}, Expected: false}, // 0 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"aws:kms"}}, Expected: true}, // 1 + {Header: http.Header{"X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": []string{"0839-9047947-844842874-481"}}, Expected: true}, // 2 + {Header: http.Header{"X-Amz-Server-Side-Encryption-Context": []string{"7PpPLAK26ONlVUGOWlusfg=="}}, Expected: true}, // 3 + { + Header: http.Header{ + "X-Amz-Server-Side-Encryption": []string{""}, + "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": []string{""}, + "X-Amz-Server-Side-Encryption-Context": []string{""}, + }, + Expected: true, + }, // 4 + { + Header: http.Header{ + "X-Amz-Server-Side-Encryption": []string{"AES256"}, + "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": []string{""}, + }, + Expected: true, + }, // 5 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"AES256"}}, Expected: false}, // 6 +} + +func TestKMSIsRequested(t *testing.T) { + for i, test := range kmsIsRequestedTests { + if got := S3KMS.IsRequested(test.Header); got != test.Expected { + t.Errorf("Test %d: Wanted %v but got %v", i, test.Expected, got) + } + } +} + var s3IsRequestedTests = []struct { Header http.Header Expected bool }{ - {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"AES256"}}, Expected: true}, // 0 - {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"AES-256"}}, Expected: true}, // 1 - {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{""}}, Expected: true}, // 2 - {Header: http.Header{"X-Amz-Server-Side-Encryptio": []string{"AES256"}}, Expected: false}, // 3 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"AES256"}}, Expected: true}, // 0 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{"AES-256"}}, Expected: true}, // 1 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{""}}, Expected: true}, // 2 + {Header: http.Header{"X-Amz-Server-Side-Encryptio": []string{"AES256"}}, Expected: false}, // 3 + {Header: http.Header{"X-Amz-Server-Side-Encryption": []string{SSEAlgorithmKMS}}, Expected: false}, // 4 } func TestS3IsRequested(t *testing.T) {