@@ -51,6 +51,7 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
51
51
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/specifying-kms-encryption.html#sse-request-headers-kms
52
52
bool use_sse_kms = auth_params.kms_key_id .length () > 0 && (method == " POST" || method == " PUT" ) &&
53
53
query.find (" uploadId" ) == std::string::npos;
54
+ bool use_sse_c = auth_params.sse_c_key .length () > 0 && auth_params.sse_c_key_md5 .length () > 0 ;
54
55
55
56
res[" x-amz-date" ] = datetime_now;
56
57
res[" x-amz-content-sha256" ] = payload_hash;
@@ -61,13 +62,18 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
61
62
res[" x-amz-server-side-encryption" ] = " aws:kms" ;
62
63
res[" x-amz-server-side-encryption-aws-kms-key-id" ] = auth_params.kms_key_id ;
63
64
}
65
+ if (use_sse_c) {
66
+ res[" x-amz-server-side-encryption-customer-algorithm" ] = " AES256" ;
67
+ res[" x-amz-server-side-encryption-customer-key" ] = auth_params.sse_c_key ;
68
+ res[" x-amz-server-side-encryption-customer-key-md5" ] = auth_params.sse_c_key_md5 ;
69
+ }
64
70
65
71
bool use_requester_pays = auth_params.requester_pays ;
66
72
if (use_requester_pays) {
67
73
res[" x-amz-request-payer" ] = " requester" ;
68
74
}
69
75
70
- string signed_headers = " " ;
76
+ string signed_headers = " " ;
71
77
hash_bytes canonical_request_hash;
72
78
hash_str canonical_request_hash_str;
73
79
if (content_type.length () > 0 ) {
@@ -80,10 +86,13 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
80
86
if (use_sse_kms) {
81
87
signed_headers += " ;x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id" ;
82
88
}
89
+ if (use_sse_c) {
90
+ signed_headers += " ;x-amz-server-side-encryption-customer-algorithm;x-amz-server-side-encryption-customer-key;x-amz-server-side-encryption-customer-key-md5" ;
91
+ }
83
92
if (use_requester_pays) {
84
93
signed_headers += " ;x-amz-request-payer" ;
85
94
}
86
- auto canonical_request = method + " \n " + S3FileSystem::UrlEncode (url) + " \n " + query;
95
+ auto canonical_request = method + " \n " + S3FileSystem::UrlEncode (url) + " \n " + query;
87
96
if (content_type.length () > 0 ) {
88
97
canonical_request += " \n content-type:" + content_type;
89
98
}
@@ -95,6 +104,11 @@ static HTTPHeaders create_s3_header(string url, string query, string host, strin
95
104
canonical_request += " \n x-amz-server-side-encryption:aws:kms" ;
96
105
canonical_request += " \n x-amz-server-side-encryption-aws-kms-key-id:" + auth_params.kms_key_id ;
97
106
}
107
+ if (use_sse_c) {
108
+ canonical_request += " \n x-amz-server-side-encryption-customer-algorithm:AES256" ;
109
+ canonical_request += " \n x-amz-server-side-encryption-customer-key:" + auth_params.sse_c_key ;
110
+ canonical_request += " \n x-amz-server-side-encryption-customer-key-md5:" + auth_params.sse_c_key_md5 ;
111
+ }
98
112
if (use_requester_pays) {
99
113
canonical_request += " \n x-amz-request-payer:requester" ;
100
114
}
@@ -154,6 +168,8 @@ void AWSEnvironmentCredentialsProvider::SetAll() {
154
168
this ->SetExtensionOptionValue (" s3_endpoint" , DUCKDB_ENDPOINT_ENV_VAR);
155
169
this ->SetExtensionOptionValue (" s3_use_ssl" , DUCKDB_USE_SSL_ENV_VAR);
156
170
this ->SetExtensionOptionValue (" s3_kms_key_id" , DUCKDB_KMS_KEY_ID_ENV_VAR);
171
+ this ->SetExtensionOptionValue (" s3_sse_c_key" , DUCKDB_SSE_C_KEY_ENV_VAR);
172
+ this ->SetExtensionOptionValue (" s3_sse_c_key_md5" , DUCKDB_SSE_C_KEY_MD5_ENV_VAR);
157
173
this ->SetExtensionOptionValue (" s3_requester_pays" , DUCKDB_REQUESTER_PAYS_ENV_VAR);
158
174
}
159
175
@@ -167,6 +183,8 @@ S3AuthParams AWSEnvironmentCredentialsProvider::CreateParams() {
167
183
params.session_token = SESSION_TOKEN_ENV_VAR;
168
184
params.endpoint = DUCKDB_ENDPOINT_ENV_VAR;
169
185
params.kms_key_id = DUCKDB_KMS_KEY_ID_ENV_VAR;
186
+ params.sse_c_key = DUCKDB_SSE_C_KEY_ENV_VAR;
187
+ params.sse_c_key_md5 = DUCKDB_SSE_C_KEY_MD5_ENV_VAR;
170
188
params.use_ssl = DUCKDB_USE_SSL_ENV_VAR;
171
189
params.requester_pays = DUCKDB_REQUESTER_PAYS_ENV_VAR;
172
190
@@ -192,6 +210,8 @@ S3AuthParams S3AuthParams::ReadFrom(optional_ptr<FileOpener> opener, FileOpenerI
192
210
secret_reader.TryGetSecretKeyOrSetting (" region" , " s3_region" , result.region );
193
211
secret_reader.TryGetSecretKeyOrSetting (" use_ssl" , " s3_use_ssl" , result.use_ssl );
194
212
secret_reader.TryGetSecretKeyOrSetting (" kms_key_id" , " s3_kms_key_id" , result.kms_key_id );
213
+ secret_reader.TryGetSecretKeyOrSetting (" sse_c_key" , " s3_sse_c_key" , result.sse_c_key );
214
+ secret_reader.TryGetSecretKeyOrSetting (" sse_c_key_md5" , " s3_sse_c_key_md5" , result.sse_c_key_md5 );
195
215
secret_reader.TryGetSecretKeyOrSetting (" s3_url_compatibility_mode" , " s3_url_compatibility_mode" ,
196
216
result.s3_url_compatibility_mode );
197
217
secret_reader.TryGetSecretKeyOrSetting (" requester_pays" , " s3_requester_pays" ,
@@ -233,6 +253,8 @@ unique_ptr<KeyValueSecret> CreateSecret(vector<string> &prefix_paths_p, string &
233
253
return_value->secret_map [" url_style" ] = params.url_style ;
234
254
return_value->secret_map [" use_ssl" ] = params.use_ssl ;
235
255
return_value->secret_map [" kms_key_id" ] = params.kms_key_id ;
256
+ return_value->secret_map [" sse_c_key" ] = params.sse_c_key ;
257
+ return_value->secret_map [" sse_c_key_md5" ] = params.sse_c_key_md5 ;
236
258
return_value->secret_map [" s3_url_compatibility_mode" ] = params.s3_url_compatibility_mode ;
237
259
return_value->secret_map [" requester_pays" ] = params.requester_pays ;
238
260
0 commit comments