Skip to content

Commit 71f5f90

Browse files
authored
feat: generate and post TDX session to session storage (#320)
1 parent c79711a commit 71f5f90

15 files changed

+450
-83
lines changed

src/main/java/com/iexec/sms/authorization/AuthorizationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public Optional<AuthorizationError> isAuthorizedOnExecutionWithDetailedIssue(fin
7878
return Optional.of(GET_CHAIN_DEAL_FAILED);
7979
}
8080

81-
final boolean isTeeTaskOnchain = TeeUtils.isTeeTag(chainDeal.getTag());
81+
final boolean isTeeTaskOnchain = TeeUtils.getTeeFramework(chainDeal.getTag()) != null;
8282
if (!isTeeTaskOnchain) {
8383
log.error("Could not match onchain task type [isTeeTaskOnchain:{}, chainTaskId:{}]",
8484
isTeeTaskOnchain, chainTaskId);

src/main/java/com/iexec/sms/ssl/SslConfig.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
import com.iexec.sms.tee.ConditionalOnTeeFramework;
2121
import lombok.Value;
2222
import lombok.extern.slf4j.Slf4j;
23-
import org.apache.hc.core5.ssl.SSLContexts;
23+
import org.apache.commons.lang3.StringUtils;
24+
import org.apache.hc.core5.ssl.SSLContextBuilder;
2425
import org.springframework.boot.context.properties.ConfigurationProperties;
2526

2627
import javax.net.ssl.SSLContext;
@@ -35,7 +36,7 @@
3536
@Slf4j
3637
@Value
3738
@ConfigurationProperties(prefix = "tee.ssl")
38-
@ConditionalOnTeeFramework(frameworks = TeeFramework.SCONE)
39+
@ConditionalOnTeeFramework(frameworks = {TeeFramework.SCONE, TeeFramework.TDX})
3940
public class SslConfig {
4041

4142
String keystore;
@@ -48,14 +49,14 @@ public class SslConfig {
4849
*/
4950
public SSLContext getFreshSslContext() {
5051
try {
51-
return SSLContexts.custom()
52-
.setKeyStoreType(keystoreType)
53-
.loadKeyMaterial(new File(keystore),
54-
keystorePassword,
55-
keystorePassword,
56-
(aliases, socket) -> keyAlias)
57-
.loadTrustMaterial(null, (chain, authType) -> true) //TODO: Add CAS certificate to truststore
58-
.build();
52+
final SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
53+
if (!StringUtils.isEmpty(keystore)) {
54+
sslContextBuilder.setKeyStoreType(keystoreType).loadKeyMaterial(
55+
new File(keystore), keystorePassword, keystorePassword,
56+
((aliases, sslParameters) -> keyAlias));
57+
}
58+
sslContextBuilder.loadTrustMaterial(null, (chain, authType) -> true); //TODO: Add CAS certificate to truststore
59+
return sslContextBuilder.build();
5960
} catch (IOException | NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException |
6061
CertificateException | KeyManagementException e) {
6162
log.warn("Failed to create a fresh SSL context", e);

src/main/java/com/iexec/sms/tee/config/TeeWorkerInternalConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public Map<String, TeeServicesProperties> sconeServicesPropertiesMap(
6565
@ConditionalOnTeeFramework(frameworks = TeeFramework.TDX)
6666
public Map<String, TeeServicesProperties> tdxServicesPropertiesMap(
6767
final TeeWorkerPipelineConfiguration pipelineConfig) {
68+
if (pipelineConfig.getPipelines().size() != 1) {
69+
throw new IllegalStateException("Only a singleton pipeline list is currently supported for TDX");
70+
}
6871
return pipelineConfig.getPipelines().stream()
6972
.map(pipeline -> new TdxServicesProperties(
7073
pipeline.version(),

src/main/java/com/iexec/sms/tee/session/TeeSessionService.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,19 @@ public TeeSessionGenerationResponse generateTeeSession(
6262
}
6363

6464
final TeeEnclaveConfiguration teeEnclaveConfiguration = taskDescription.getAppEnclaveConfiguration();
65-
if (teeEnclaveConfiguration == null) {
65+
if (taskDescription.requiresSgx() && teeEnclaveConfiguration == null) {
6666
throw new TeeSessionGenerationException(
6767
APP_COMPUTE_NO_ENCLAVE_CONFIG,
6868
String.format("TEE enclave configuration can't be null [taskId:%s]", taskId));
6969
}
7070

7171
final TeeServicesProperties teeServicesProperties;
72-
7372
try {
74-
teeServicesProperties = resolveTeeServiceProperties(teeEnclaveConfiguration.getVersion());
73+
if (taskDescription.requiresSgx()) {
74+
teeServicesProperties = resolveTeeServiceProperties(teeEnclaveConfiguration.getVersion());
75+
} else {
76+
teeServicesProperties = teeServicesPropertiesMap.values().stream().findFirst().orElseThrow();
77+
}
7578
} catch (NoSuchElementException e) {
7679
// TODO Add appropriate error type
7780
throw new TeeSessionGenerationException(
@@ -94,7 +97,6 @@ public TeeSessionGenerationResponse generateTeeSession(
9497
String.format("TEE framework can't be null [taskId:%s]", taskId));
9598
}
9699

97-
// /!\ TODO clean expired tasks sessions
98100
final String secretProvisioningUrl = teeSessionHandler.buildAndPostSession(request);
99101
return new TeeSessionGenerationResponse(sessionId, secretProvisioningUrl);
100102
}

src/main/java/com/iexec/sms/tee/session/base/SecretSessionBaseService.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,20 +308,22 @@ SecretEnclaveBase getAppTokens(final TeeSessionRequest request) throws TeeSessio
308308
final TaskDescription taskDescription = request.getTaskDescription();
309309

310310
final Map<String, String> tokens = new HashMap<>();
311-
final TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration();
312-
if (enclaveConfig == null) {
313-
throw new TeeSessionGenerationException(
314-
APP_COMPUTE_NO_ENCLAVE_CONFIG,
315-
"Enclave configuration must not be null");
316-
}
317-
if (!enclaveConfig.getValidator().isValid()) {
318-
throw new TeeSessionGenerationException(
319-
APP_COMPUTE_INVALID_ENCLAVE_CONFIG,
320-
"Invalid enclave configuration: " +
321-
enclaveConfig.getValidator().validate().toString());
322-
}
311+
if (taskDescription.requiresSgx()) {
312+
final TeeEnclaveConfiguration enclaveConfig = taskDescription.getAppEnclaveConfiguration();
313+
if (enclaveConfig == null) {
314+
throw new TeeSessionGenerationException(
315+
APP_COMPUTE_NO_ENCLAVE_CONFIG,
316+
"Enclave configuration must not be null");
317+
}
318+
if (!enclaveConfig.getValidator().isValid()) {
319+
throw new TeeSessionGenerationException(
320+
APP_COMPUTE_INVALID_ENCLAVE_CONFIG,
321+
"Invalid enclave configuration: " +
322+
enclaveConfig.getValidator().validate().toString());
323+
}
323324

324-
enclaveBase.mrenclave(enclaveConfig.getFingerprint());
325+
enclaveBase.mrenclave(enclaveConfig.getFingerprint());
326+
}
325327

326328
final Map<String, String> computeSecrets = getApplicationComputeSecrets(taskDescription);
327329
tokens.putAll(computeSecrets);

src/main/java/com/iexec/sms/tee/session/tdx/TdxSessionHandlerService.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,40 @@
1616

1717
package com.iexec.sms.tee.session.tdx;
1818

19+
import com.iexec.common.utils.FeignBuilder;
1920
import com.iexec.commons.poco.tee.TeeFramework;
2021
import com.iexec.sms.api.TeeSessionGenerationError;
22+
import com.iexec.sms.ssl.SslConfig;
2123
import com.iexec.sms.tee.ConditionalOnTeeFramework;
2224
import com.iexec.sms.tee.session.generic.TeeSessionGenerationException;
2325
import com.iexec.sms.tee.session.generic.TeeSessionHandler;
2426
import com.iexec.sms.tee.session.generic.TeeSessionRequest;
27+
import com.iexec.sms.tee.session.tdx.storage.TdxSession;
28+
import com.iexec.sms.tee.session.tdx.storage.TdxSessionStorageApiClient;
29+
import com.iexec.sms.tee.session.tdx.storage.TdxSessionStorageConfiguration;
30+
import feign.Client;
31+
import feign.Logger;
32+
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
2533
import org.springframework.stereotype.Service;
2634

2735
@Service
2836
@ConditionalOnTeeFramework(frameworks = TeeFramework.TDX)
2937
public class TdxSessionHandlerService implements TeeSessionHandler {
38+
private final TdxSessionMakerService sessionService;
39+
private final TdxSessionStorageConfiguration storageConfiguration;
40+
private final TdxSessionStorageApiClient storageClient;
41+
42+
public TdxSessionHandlerService(
43+
final SslConfig sslConfig,
44+
final TdxSessionMakerService sessionService,
45+
final TdxSessionStorageConfiguration storageConfiguration) {
46+
this.sessionService = sessionService;
47+
this.storageConfiguration = storageConfiguration;
48+
this.storageClient = FeignBuilder.createBuilder(Logger.Level.FULL)
49+
.client(new Client.Default(sslConfig.getFreshSslContext().getSocketFactory(), NoopHostnameVerifier.INSTANCE))
50+
.target(TdxSessionStorageApiClient.class, storageConfiguration.getPostUrl());
51+
}
52+
3053
/**
3154
* Build and post secret session on secret provisioning service.
3255
*
@@ -36,9 +59,15 @@ public class TdxSessionHandlerService implements TeeSessionHandler {
3659
*/
3760
@Override
3861
public String buildAndPostSession(final TeeSessionRequest request) throws TeeSessionGenerationException {
39-
throw new TeeSessionGenerationException(
40-
TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED,
41-
"Not implemented yet"
42-
);
62+
final TdxSession session = sessionService.generateSession(request);
63+
64+
try {
65+
storageClient.postSession(session);
66+
return storageConfiguration.getRemoteAttestationUrl();
67+
} catch (Exception e) {
68+
throw new TeeSessionGenerationException(
69+
TeeSessionGenerationError.SECURE_SESSION_STORAGE_CALL_FAILED,
70+
"Failed to post session: " + e.getMessage());
71+
}
4372
}
4473
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2025 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.sms.tee.session.tdx;
18+
19+
import com.iexec.commons.poco.tee.TeeFramework;
20+
import com.iexec.sms.api.config.TeeAppProperties;
21+
import com.iexec.sms.tee.ConditionalOnTeeFramework;
22+
import com.iexec.sms.tee.session.base.SecretEnclaveBase;
23+
import com.iexec.sms.tee.session.base.SecretSessionBase;
24+
import com.iexec.sms.tee.session.base.SecretSessionBaseService;
25+
import com.iexec.sms.tee.session.generic.TeeSessionGenerationException;
26+
import com.iexec.sms.tee.session.generic.TeeSessionRequest;
27+
import com.iexec.sms.tee.session.tdx.storage.TdxSession;
28+
import org.springframework.stereotype.Service;
29+
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
33+
@Service
34+
@ConditionalOnTeeFramework(frameworks = TeeFramework.TDX)
35+
public class TdxSessionMakerService {
36+
public static final String TDX_SESSION_VERSION = "0.1.0";
37+
private final SecretSessionBaseService secretSessionBaseService;
38+
39+
public TdxSessionMakerService(final SecretSessionBaseService secretSessionBaseService) {
40+
this.secretSessionBaseService = secretSessionBaseService;
41+
}
42+
43+
public TdxSession generateSession(final TeeSessionRequest request) throws TeeSessionGenerationException {
44+
final SecretSessionBase baseSession = secretSessionBaseService.getSecretsTokens(request);
45+
final List<TdxSession.Service> tdxEnclaves = new ArrayList<>();
46+
if (baseSession.getPreCompute() != null) {
47+
tdxEnclaves.add(toTdxEnclave(baseSession.getPreCompute(), request.getTeeServicesProperties().getPreComputeProperties()));
48+
}
49+
// FIXME fingerprint should be dapp checksum from TaskDescription after commons-poco update
50+
tdxEnclaves.add(toTdxEnclave(baseSession.getAppCompute(), request.getTaskDescription().getAppUri(), ""));
51+
tdxEnclaves.add(toTdxEnclave(baseSession.getPostCompute(), request.getTeeServicesProperties().getPostComputeProperties()));
52+
return new TdxSession(request.getSessionId(), TDX_SESSION_VERSION, List.copyOf(tdxEnclaves));
53+
}
54+
55+
private TdxSession.Service toTdxEnclave(final SecretEnclaveBase enclaveBase, final TeeAppProperties teeAppProperties) {
56+
return toTdxEnclave(enclaveBase, teeAppProperties.getImage(), teeAppProperties.getFingerprint());
57+
}
58+
59+
private TdxSession.Service toTdxEnclave(final SecretEnclaveBase enclaveBase, final String image_name, final String fingerprint) {
60+
return new TdxSession.Service(
61+
enclaveBase.getName(), image_name, fingerprint, enclaveBase.getEnvironment()
62+
);
63+
}
64+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2025 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.sms.tee.session.tdx.storage;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
public record TdxSession(String name, String version, List<Service> services) {
23+
public record Service(String name, String image_name, String fingerprint, Map<String, String> environment) {
24+
}
25+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2025 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.sms.tee.session.tdx.storage;
18+
19+
import feign.RequestLine;
20+
21+
public interface TdxSessionStorageApiClient {
22+
@RequestLine("POST /session")
23+
String postSession(TdxSession tdxSession);
24+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2025 IEXEC BLOCKCHAIN TECH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.iexec.sms.tee.session.tdx.storage;
18+
19+
import com.iexec.commons.poco.tee.TeeFramework;
20+
import com.iexec.sms.tee.ConditionalOnTeeFramework;
21+
import lombok.Value;
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
24+
@Value
25+
@ConfigurationProperties(prefix = "tee.secret-provisioner")
26+
@ConditionalOnTeeFramework(frameworks = TeeFramework.TDX)
27+
public class TdxSessionStorageConfiguration {
28+
String postUrl;
29+
String remoteAttestationUrl;
30+
}

0 commit comments

Comments
 (0)