1616import com .google .gson .Gson ;
1717import com .google .gson .GsonBuilder ;
1818
19+ import io .opentdf .platform .wellknownconfiguration .WellKnownServiceClientInterface ;
20+ import org .bouncycastle .jcajce .provider .asymmetric .ec .KeyFactorySpi ;
1921import org .bouncycastle .jce .interfaces .ECPublicKey ;
2022import org .slf4j .Logger ;
2123import org .slf4j .LoggerFactory ;
@@ -65,6 +67,17 @@ public InvalidNanoTDFConfig(String errorMessage) {
6567 }
6668 }
6769
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+
6881 private Config .HeaderInfo getHeaderInfo (Config .NanoTDFConfig nanoTDFConfig ) throws InvalidNanoTDFConfig , UnsupportedNanoTDFFeature {
6982 if (nanoTDFConfig .collectionConfig .useCollection ) {
7083 Config .HeaderInfo headerInfo = nanoTDFConfig .collectionConfig .getHeaderInfo ();
@@ -74,22 +87,19 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
7487 }
7588
7689 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 ()));
8091
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" );
8694 }
8795
96+ var kasInfo = maybeKas .get ();
97+
8898 // 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 );
90100 assert kasURL .getIdentifier () != null : "Identifier in ResourceLocator cannot be null" ;
91101
92- ECKeyPair keyPair = new ECKeyPair (nanoTDFConfig . eccMode . getCurveName () , ECKeyPair .ECAlgorithm .ECDSA );
102+ ECKeyPair keyPair = new ECKeyPair (kasInfo . Algorithm , ECKeyPair .ECAlgorithm .ECDSA );
93103
94104 // Generate symmetric key
95105 ECPublicKey kasPublicKey = ECKeyPair .publicKeyFromPem (kasInfo .PublicKey );
@@ -138,7 +148,12 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
138148 // Create header
139149 byte [] compressedPubKey = keyPair .compressECPublickey ();
140150 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 );
142157 header .setPayloadConfig (nanoTDFConfig .config );
143158 header .setEphemeralKey (compressedPubKey );
144159 header .setKasLocator (kasURL );
@@ -152,6 +167,21 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) thro
152167 return headerInfo ;
153168 }
154169
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+
155185 public int createNanoTDF (ByteBuffer data , OutputStream outputStream ,
156186 Config .NanoTDFConfig nanoTDFConfig ) throws SDKException , IOException {
157187 int nanoTDFSize = 0 ;
0 commit comments