Skip to content

Commit e6c84b8

Browse files
strantalisgithub-actions[bot]
authored andcommitted
feat(sdk): expose SRT signer (#329)
Signed-off-by: strantalis <strantalis@virtru.com> (cherry picked from commit f93d332)
1 parent 17c0b89 commit e6c84b8

8 files changed

Lines changed: 297 additions & 24 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.opentdf.platform.sdk;
2+
3+
import com.nimbusds.jose.JOSEException;
4+
import com.nimbusds.jose.JWSAlgorithm;
5+
import com.nimbusds.jose.JWSHeader;
6+
import com.nimbusds.jose.crypto.RSASSASigner;
7+
import com.nimbusds.jose.jwk.RSAKey;
8+
9+
final class DefaultSrtSigner implements SrtSigner {
10+
private static final JWSHeader HEADER = new JWSHeader.Builder(JWSAlgorithm.RS256).build();
11+
private final RSASSASigner signer;
12+
13+
DefaultSrtSigner(RSAKey rsaKey) {
14+
try {
15+
this.signer = new RSASSASigner(rsaKey);
16+
} catch (JOSEException e) {
17+
throw new SDKException("error creating SRT signer", e);
18+
}
19+
}
20+
21+
@Override
22+
public byte[] sign(byte[] input) throws java.security.GeneralSecurityException {
23+
try {
24+
return signer.sign(HEADER, input).decode();
25+
} catch (JOSEException e) {
26+
throw new java.security.GeneralSecurityException("error signing SRT payload", e);
27+
}
28+
}
29+
30+
@Override
31+
public String alg() {
32+
return JWSAlgorithm.RS256.getName();
33+
}
34+
}

sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import com.nimbusds.jose.JOSEException;
88
import com.nimbusds.jose.JWSAlgorithm;
99
import com.nimbusds.jose.JWSHeader;
10-
import com.nimbusds.jose.crypto.RSASSASigner;
11-
import com.nimbusds.jose.jwk.RSAKey;
10+
import com.nimbusds.jose.JWSSigner;
11+
import com.nimbusds.jose.util.Base64URL;
12+
import com.nimbusds.jose.jca.JCAContext;
1213
import com.nimbusds.jwt.JWTClaimsSet;
1314
import com.nimbusds.jwt.SignedJWT;
1415
import io.opentdf.platform.kas.AccessServiceClient;
@@ -28,6 +29,7 @@
2829
import java.util.Collections;
2930
import java.util.Date;
3031
import java.util.HashMap;
32+
import java.util.Set;
3133
import java.util.function.BiFunction;
3234

3335
import static io.opentdf.platform.sdk.TDF.GLOBAL_KEY_SALT;
@@ -42,7 +44,7 @@ class KASClient implements SDK.KAS {
4244
private final OkHttpClient httpClient;
4345
private final BiFunction<OkHttpClient, String, ProtocolClient> protocolClientFactory;
4446
private final boolean usePlaintext;
45-
private final RSASSASigner signer;
47+
private final JWSSigner signer;
4648
private AsymDecryption decryptor;
4749
private String clientPublicKey;
4850
private KASKeyCache kasKeyCache;
@@ -53,17 +55,16 @@ class KASClient implements SDK.KAS {
5355
* A client that communicates with KAS
5456
*
5557
* communicate
56-
* @param dpopKey
58+
* @param srtSigner
5759
*/
58-
KASClient(OkHttpClient httpClient, BiFunction<OkHttpClient, String, ProtocolClient> protocolClientFactory, RSAKey dpopKey, boolean usePlaintext) {
60+
KASClient(OkHttpClient httpClient, BiFunction<OkHttpClient, String, ProtocolClient> protocolClientFactory, SrtSigner srtSigner, boolean usePlaintext) {
5961
this.httpClient = httpClient;
6062
this.protocolClientFactory = protocolClientFactory;
6163
this.usePlaintext = usePlaintext;
62-
try {
63-
this.signer = new RSASSASigner(dpopKey);
64-
} catch (JOSEException e) {
65-
throw new SDKException("error creating dpop signer", e);
64+
if (srtSigner == null) {
65+
throw new SDKException("srtSigner must be provided");
6666
}
67+
this.signer = new SrtJwsSigner(srtSigner);
6768
this.kasKeyCache = new KASKeyCache();
6869
}
6970

@@ -197,4 +198,40 @@ synchronized AccessServiceClient getStub(String url) {
197198
return new AccessServiceClient(client);
198199
});
199200
}
201+
202+
private static final class SrtJwsSigner implements JWSSigner {
203+
private static final JWSAlgorithm EXPECTED_ALG = JWSAlgorithm.RS256;
204+
private final SrtSigner srtSigner;
205+
private final JCAContext jcaContext = new JCAContext();
206+
207+
private SrtJwsSigner(SrtSigner srtSigner) {
208+
this.srtSigner = srtSigner;
209+
if (!EXPECTED_ALG.getName().equals(srtSigner.alg())) {
210+
throw new SDKException("unsupported SRT signing algorithm: " + srtSigner.alg());
211+
}
212+
}
213+
214+
@Override
215+
public Base64URL sign(JWSHeader header, byte[] signingInput) throws JOSEException {
216+
if (!EXPECTED_ALG.equals(header.getAlgorithm())) {
217+
throw new JOSEException("SRT signer algorithm mismatch: " + header.getAlgorithm());
218+
}
219+
220+
try {
221+
return Base64URL.encode(srtSigner.sign(signingInput));
222+
} catch (java.security.GeneralSecurityException e) {
223+
throw new JOSEException("error signing SRT payload", e);
224+
}
225+
}
226+
227+
@Override
228+
public Set<JWSAlgorithm> supportedJWSAlgorithms() {
229+
return Collections.singleton(EXPECTED_ALG);
230+
}
231+
232+
@Override
233+
public JCAContext getJCAContext() {
234+
return jcaContext;
235+
}
236+
}
200237
}

sdk/src/main/java/io/opentdf/platform/sdk/SDK.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class SDK implements AutoCloseable {
3131
private final Interceptor authInterceptor;
3232
private final String platformUrl;
3333
private final ProtocolClient platformServicesClient;
34+
private final SrtSigner srtSigner;
3435

3536
/**
3637
* Closes the SDK, including its associated services.
@@ -87,12 +88,13 @@ public Optional<Interceptor> getAuthInterceptor() {
8788
return Optional.ofNullable(authInterceptor);
8889
}
8990

90-
SDK(Services services, TrustManager trustManager, Interceptor authInterceptor, ProtocolClient platformServicesClient, String platformUrl) {
91+
SDK(Services services, TrustManager trustManager, Interceptor authInterceptor, ProtocolClient platformServicesClient, String platformUrl, SrtSigner srtSigner) {
9192
this.platformUrl = platformUrl;
9293
this.services = services;
9394
this.trustManager = trustManager;
9495
this.authInterceptor = authInterceptor;
9596
this.platformServicesClient = platformServicesClient;
97+
this.srtSigner = srtSigner;
9698
}
9799

98100
public Services getServices() {
@@ -122,6 +124,10 @@ public ProtocolClient getPlatformServicesClient() {
122124
return this.platformServicesClient;
123125
}
124126

127+
public Optional<SrtSigner> getSrtSigner() {
128+
return Optional.ofNullable(srtSigner);
129+
}
130+
125131
/**
126132
* Checks to see if this has the structure of a Z-TDF in that it is a zip file
127133
* containing

sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class SDKBuilder {
6666
private SSLFactory sslFactory;
6767
private AuthorizationGrant authzGrant;
6868
private ProtocolType protocolType = ProtocolType.CONNECT;
69+
private SrtSigner srtSigner;
6970

7071
private static final Logger logger = LoggerFactory.getLogger(SDKBuilder.class);
7172

@@ -177,6 +178,11 @@ public SDKBuilder protocol(ProtocolType protocolType) {
177178
return this;
178179
}
179180

181+
public SDKBuilder srtSigner(SrtSigner signer) {
182+
this.srtSigner = signer;
183+
return this;
184+
}
185+
180186
private Interceptor getAuthInterceptor(RSAKey rsaKey) {
181187
if (platformEndpoint == null) {
182188
throw new SDKException("cannot build an SDK without specifying the platform endpoint");
@@ -236,14 +242,16 @@ static class ServicesAndInternals {
236242
final Interceptor interceptor;
237243
final TrustManager trustManager;
238244
final ProtocolClient protocolClient;
245+
final SrtSigner srtSigner;
239246

240247
final SDK.Services services;
241248

242-
ServicesAndInternals(Interceptor interceptor, TrustManager trustManager, SDK.Services services, ProtocolClient protocolClient) {
249+
ServicesAndInternals(Interceptor interceptor, TrustManager trustManager, SDK.Services services, ProtocolClient protocolClient, SrtSigner srtSigner) {
243250
this.interceptor = interceptor;
244251
this.trustManager = trustManager;
245252
this.services = services;
246253
this.protocolClient = protocolClient;
254+
this.srtSigner = srtSigner;
247255
}
248256
}
249257

@@ -267,7 +275,8 @@ ServicesAndInternals buildServices() {
267275

268276
this.platformEndpoint = AddressNormalizer.normalizeAddress(this.platformEndpoint, this.usePlainText);
269277
var authInterceptor = getAuthInterceptor(dpopKey);
270-
var kasClient = getKASClient(dpopKey, authInterceptor);
278+
var srtSignerToUse = this.srtSigner == null ? new DefaultSrtSigner(dpopKey) : this.srtSigner;
279+
var kasClient = getKASClient(srtSignerToUse, authInterceptor);
271280
var httpClient = getHttpClient();
272281
var client = getProtocolClient(platformEndpoint, httpClient, authInterceptor);
273282
var attributeService = new AttributesServiceClient(client);
@@ -337,18 +346,19 @@ public SDK.KAS kas() {
337346
authInterceptor,
338347
sslFactory == null ? null : sslFactory.getTrustManager().orElse(null),
339348
services,
340-
client);
349+
client,
350+
srtSignerToUse);
341351
}
342352

343353
@Nonnull
344-
private KASClient getKASClient(RSAKey dpopKey, Interceptor interceptor) {
354+
private KASClient getKASClient(SrtSigner srtSigner, Interceptor interceptor) {
345355
BiFunction<OkHttpClient, String, ProtocolClient> protocolClientFactory = (OkHttpClient client, String address) -> getProtocolClient(address, client, interceptor);
346-
return new KASClient(getHttpClient(), protocolClientFactory, dpopKey, usePlainText);
356+
return new KASClient(getHttpClient(), protocolClientFactory, srtSigner, usePlainText);
347357
}
348358

349359
public SDK build() {
350360
var services = buildServices();
351-
return new SDK(services.services, services.trustManager, services.interceptor, services.protocolClient, platformEndpoint);
361+
return new SDK(services.services, services.trustManager, services.interceptor, services.protocolClient, platformEndpoint, services.srtSigner);
352362
}
353363

354364
private ProtocolClient getUnauthenticatedProtocolClient(String endpoint, OkHttpClient httpClient) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package io.opentdf.platform.sdk;
2+
3+
public interface SrtSigner {
4+
byte[] sign(byte[] input) throws java.security.GeneralSecurityException;
5+
6+
String alg();
7+
}

0 commit comments

Comments
 (0)