16
16
import com .google .gson .Gson ;
17
17
import com .google .gson .GsonBuilder ;
18
18
19
+ import io .opentdf .platform .wellknownconfiguration .WellKnownServiceClientInterface ;
20
+ import org .bouncycastle .jcajce .provider .asymmetric .ec .KeyFactorySpi ;
19
21
import org .bouncycastle .jce .interfaces .ECPublicKey ;
20
22
import org .slf4j .Logger ;
21
23
import org .slf4j .LoggerFactory ;
@@ -65,6 +67,17 @@ public InvalidNanoTDFConfig(String errorMessage) {
65
67
}
66
68
}
67
69
70
+ private static Optional <Config .KASInfo > getBaseKey (WellKnownServiceClientInterface wellKnownService ) {
71
+ var key = Planner .fetchBaseKey (wellKnownService );
72
+ key .ifPresent (k -> {
73
+ if (!KeyType .fromAlgorithm (k .getPublicKey ().getAlgorithm ()).isEc ()) {
74
+ throw new SDKException (String .format ("base key is not an EC key, cannot create NanoTDF using a key of type %s" ,
75
+ k .getPublicKey ().getAlgorithm ()));
76
+ }
77
+ });
78
+ return key .map (Config .KASInfo ::fromSimpleKasKey );
79
+ }
80
+
68
81
private Config .HeaderInfo getHeaderInfo (Config .NanoTDFConfig nanoTDFConfig ) throws InvalidNanoTDFConfig , UnsupportedNanoTDFFeature {
69
82
if (nanoTDFConfig .collectionConfig .useCollection ) {
70
83
Config .HeaderInfo headerInfo = nanoTDFConfig .collectionConfig .getHeaderInfo ();
@@ -74,22 +87,19 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
74
87
}
75
88
76
89
Gson gson = new GsonBuilder ().create ();
77
- if (nanoTDFConfig .kasInfoList .isEmpty ()) {
78
- throw new InvalidNanoTDFConfig ("kas url is missing" );
79
- }
90
+ Optional <Config .KASInfo > maybeKas = getKasInfo (nanoTDFConfig ).or (() -> NanoTDF .getBaseKey (services .wellknown ()));
80
91
81
- Config .KASInfo kasInfo = nanoTDFConfig .kasInfoList .get (0 );
82
- String url = kasInfo .URL ;
83
- if (kasInfo .PublicKey == null || kasInfo .PublicKey .isEmpty ()) {
84
- logger .info ("no public key provided for KAS at {}, retrieving" , url );
85
- kasInfo = services .kas ().getECPublicKey (kasInfo , nanoTDFConfig .eccMode .getEllipticCurveType ());
92
+ if (maybeKas .isEmpty ()) {
93
+ throw new SDKException ("no KAS info provided and couldn't get base key, cannot create NanoTDF" );
86
94
}
87
95
96
+ var kasInfo = maybeKas .get ();
97
+
88
98
// Kas url resource locator
89
- ResourceLocator kasURL = new ResourceLocator (nanoTDFConfig . kasInfoList . get ( 0 ) .URL , kasInfo .KID );
99
+ ResourceLocator kasURL = new ResourceLocator (kasInfo .URL , kasInfo .KID );
90
100
assert kasURL .getIdentifier () != null : "Identifier in ResourceLocator cannot be null" ;
91
101
92
- ECKeyPair keyPair = new ECKeyPair (nanoTDFConfig . eccMode . getCurveName () , ECKeyPair .ECAlgorithm .ECDSA );
102
+ ECKeyPair keyPair = new ECKeyPair (kasInfo . Algorithm , ECKeyPair .ECAlgorithm .ECDSA );
93
103
94
104
// Generate symmetric key
95
105
ECPublicKey kasPublicKey = ECKeyPair .publicKeyFromPem (kasInfo .PublicKey );
@@ -138,7 +148,12 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
138
148
// Create header
139
149
byte [] compressedPubKey = keyPair .compressECPublickey ();
140
150
Header header = new Header ();
141
- header .setECCMode (nanoTDFConfig .eccMode );
151
+ var mode = new ECCMode ();
152
+ mode .setEllipticCurve (Enum .valueOf (NanoTDFType .ECCurve .class , keyPair .curveName ()));
153
+ if (logger .isWarnEnabled () && !nanoTDFConfig .eccMode .equals (mode )) {
154
+ logger .warn ("ECC mode provided in NanoTDFConfig: {}, ECC mode from key: {}" , nanoTDFConfig .eccMode , mode );
155
+ }
156
+ header .setECCMode (mode );
142
157
header .setPayloadConfig (nanoTDFConfig .config );
143
158
header .setEphemeralKey (compressedPubKey );
144
159
header .setKasLocator (kasURL );
@@ -152,6 +167,21 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
152
167
return headerInfo ;
153
168
}
154
169
170
+ private Optional <Config .KASInfo > getKasInfo (Config .NanoTDFConfig nanoTDFConfig ) {
171
+ if (nanoTDFConfig .kasInfoList .isEmpty ()) {
172
+ logger .debug ("no kas info provided in NanoTDFConfig" );
173
+ return Optional .empty ();
174
+ }
175
+
176
+ Config .KASInfo kasInfo = nanoTDFConfig .kasInfoList .get (0 );
177
+ String url = kasInfo .URL ;
178
+ if (kasInfo .PublicKey == null || kasInfo .PublicKey .isEmpty ()) {
179
+ logger .info ("no public key provided for KAS at {}, retrieving" , url );
180
+ kasInfo = services .kas ().getECPublicKey (kasInfo , nanoTDFConfig .eccMode .getEllipticCurveType ());
181
+ }
182
+ return Optional .of (kasInfo );
183
+ }
184
+
155
185
public int createNanoTDF (ByteBuffer data , OutputStream outputStream ,
156
186
Config .NanoTDFConfig nanoTDFConfig ) throws SDKException , IOException {
157
187
int nanoTDFSize = 0 ;
0 commit comments