2323import io .vertx .ext .auth .PubSecKeyOptions ;
2424import io .vertx .ext .auth .impl .CertificateHelper ;
2525import io .vertx .ext .auth .impl .asn .ASN1 ;
26+ import io .vertx .ext .auth .impl .jose .algo .MacSigningAlgorithm ;
27+ import io .vertx .ext .auth .impl .jose .algo .PubKeySigningAlgorithm ;
28+ import io .vertx .ext .auth .impl .jose .algo .Signer ;
29+ import io .vertx .ext .auth .impl .jose .algo .SigningAlgorithm ;
2630
2731import javax .crypto .Mac ;
2832import javax .crypto .spec .SecretKeySpec ;
3337import java .security .cert .*;
3438import java .security .spec .*;
3539import java .util .*;
40+ import java .util .concurrent .Callable ;
3641import java .util .regex .Matcher ;
3742import java .util .regex .Pattern ;
43+ import java .util .stream .Collectors ;
44+ import java .util .stream .Stream ;
3845
3946import static io .vertx .ext .auth .impl .Codec .base64MimeDecode ;
4047import static io .vertx .ext .auth .impl .Codec .base64UrlDecode ;
6067 */
6168public final class JWK {
6269
63- private static final Logger LOG = LoggerFactory .getLogger (JWK .class );
64-
65- private static final Map <String , List <String >> ALG_ALIAS = new HashMap <String , List <String >>() {{
66- put ("HS256" , Arrays .asList (
67- // JCE
68- "HMacSHA256" ,
69- // OID
70- "1.2.840.113549.2.9" ));
71- put ("HS384" , Arrays .asList (
72- // JCE
73- "HMacSHA384" ,
74- // OID
75- "1.2.840.113549.2.10" ));
76- put ("HS512" , Arrays .asList (
77- // JCE
78- "HMacSHA512" ,
79- // OID
80- "1.2.840.113549.2.11" ));
81- put ("RS256" , Arrays .asList (
82- // JCE
83- "SHA256withRSA" ,
84- // OID
85- "1.2.840.113549.1.1.11" ));
86- put ("RS384" , Arrays .asList (
87- // JCE
88- "SHA384withRSA" ,
89- // OID
90- "1.2.840.113549.1.1.12" ));
91- put ("RS512" , Arrays .asList (
92- // JCE
93- "SHA512withRSA" ,
94- // OID
95- "1.2.840.113549.1.1.13" ));
96- put ("ES256K" , Collections .singletonList ("SHA256withECDSA" ));
97- put ("ES256" , Arrays .asList (
98- // JCE
99- "SHA256withECDSA" ,
100- // OID
101- "1.2.840.10045.4.3.2" ));
102- put ("ES384" , Arrays .asList (
103- // JCE
104- "SHA384withECDSA" ,
105- // OID
106- "1.2.840.10045.4.3.3" ));
107- put ("ES512" , Arrays .asList (
108- // JCE
109- "SHA512withECDSA" ,
110- // OID
111- "1.2.840.10045.4.3.4" ));
112- }};
113-
114- private static boolean invalidAlgAlias (String alg , String alias ) {
115- for (String expected : ALG_ALIAS .get (alias )) {
116- if (alg .equalsIgnoreCase (expected )) {
117- return false ;
118- }
119- }
120- return true ;
121- }
70+ static final Logger LOG = LoggerFactory .getLogger (JWK .class );
12271
12372 // JSON JWK properties
12473 private final String kid ;
@@ -136,61 +85,22 @@ private static boolean invalidAlgAlias(String alg, String alias) {
13685 private final SigningAlgorithm signingAlgorithm ;
13786
13887 public static List <JWK > load (KeyStore keyStore , String keyStorePassword , Map <String , String > passwordProtection ) {
139- final List <JWK > keys = new ArrayList <>();
140-
141- // load MACs
142- for (String alias : Arrays .asList ("HS256" , "HS384" , "HS512" )) {
143- try {
144- char [] password = password (keyStorePassword , passwordProtection , alias );
145- final Key secretKey = keyStore .getKey (alias , password );
146- // key store does not have the requested algorithm
147- if (secretKey == null ) {
148- continue ;
149- }
150- // test the algorithm
151- String alg = secretKey .getAlgorithm ();
152- // the algorithm cannot be null, and it cannot be different from the alias list
153- if (invalidAlgAlias (alg , alias )) {
154- LOG .warn ("The key algorithm does not match: {" + alias + ": " + alg + "}" );
155- continue ;
156- }
157- // algorithm is valid
158- Mac mac = Mac .getInstance (alg );
159- mac .init (secretKey );
160- keys .add (new JWK (alias , mac ));
161- } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | InvalidKeyException e ) {
162- LOG .warn ("Failed to load key for algorithm: " + alias , e );
163- }
164- }
165-
166- for (String alias : Arrays .asList ("RS256" , "RS384" , "RS512" , "ES256K" , "ES256" , "ES384" , "ES512" )) {
88+ final List <Callable <SigningAlgorithm >> keys = SigningAlgorithm .create (keyStore , keyStorePassword , passwordProtection );
89+ return keys .stream ().flatMap (fact -> {
16790 try {
168- // Key pairs on keystores are stored with a certificate, so we use it to load a key pair
169- X509Certificate certificate = (X509Certificate ) keyStore .getCertificate (alias );
170- // not found
171- if (certificate == null ) {
172- continue ;
91+ SigningAlgorithm algo = fact .call ();
92+ if (algo instanceof PubKeySigningAlgorithm ) {
93+ PubKeySigningAlgorithm psa = (PubKeySigningAlgorithm ) algo ;
94+ return Stream .of (new JWK (psa .name (), psa .id (), psa ));
95+ } else {
96+ MacSigningAlgorithm msa = (MacSigningAlgorithm ) algo ;
97+ return Stream .of (new JWK (msa ));
17398 }
174- // start validation
175- certificate .checkValidity ();
176- // verify that the algorithms match
177- String alg = certificate .getSigAlgName ();
178- // the algorithm cannot be null, and it cannot be different from the alias list
179- if (invalidAlgAlias (alg , alias )) {
180- LOG .warn ("The key algorithm does not match: {" + alias + ": " + alg + "}" );
181- continue ;
182- }
183- // algorithm is valid
184- char [] password = password (keyStorePassword , passwordProtection , alias );
185- PrivateKey privateKey = (PrivateKey ) keyStore .getKey (alias , password );
186- keys .add (new JWK (alias , certificate , privateKey ));
187- } catch (ClassCastException | KeyStoreException | CertificateExpiredException | CertificateNotYetValidException |
188- NoSuchAlgorithmException | UnrecoverableKeyException e ) {
189- LOG .warn ("Failed to load key for algorithm: " + alias , e );
99+ } catch (Exception e ) {
100+ LOG .warn ("Failed to load key for algorithm" , e );
101+ return Stream .empty ();
190102 }
191- }
192-
193- return keys ;
103+ }).collect (Collectors .toList ());
194104 }
195105
196106 private static char [] password (String keyStorePassword , Map <String , String > passwordProtection , String alias ) {
@@ -330,78 +240,69 @@ private static PubKeySigningAlgorithm parsePEM(String alg, KeyFactory kf, String
330240 case "CERTIFICATE" :
331241 final CertificateFactory cf = CertificateFactory .getInstance ("X.509" );
332242 publicKey = cf .generateCertificate (new ByteArrayInputStream (pem .getBytes (StandardCharsets .US_ASCII ))).getPublicKey ();
333- return createPubKeySigningAlgorithm (alg , null , publicKey );
243+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , publicKey );
334244 case "PUBLIC KEY" :
335245 case "PUBLIC RSA KEY" :
336246 case "RSA PUBLIC KEY" :
337247 publicKey = kf .generatePublic (new X509EncodedKeySpec (base64MimeDecode (buffer .getBytes ())));
338- return createPubKeySigningAlgorithm (alg , null , publicKey );
248+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , publicKey );
339249 case "PRIVATE KEY" :
340250 case "PRIVATE RSA KEY" :
341251 case "RSA PRIVATE KEY" :
342252 privateKey = kf .generatePrivate (new PKCS8EncodedKeySpec (base64MimeDecode (buffer .getBytes ())));
343- return createPubKeySigningAlgorithm (alg , privateKey , null );
253+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , privateKey );
344254 default :
345255 throw new IllegalStateException ("Invalid PEM content: " + kind );
346256 }
347257 }
348258
349- private JWK (String algorithm , Mac mac ) throws NoSuchAlgorithmException {
259+ private JWK (MacSigningAlgorithm algo ) throws NoSuchAlgorithmException {
350260
351261 kid = null ;
352- label = algorithm + "#" + mac .hashCode ();
262+ label = algo . name () + "#" + algo . mac () .hashCode ();
353263 use = null ;
354264 kty = "oct" ;
355265
356- switch (algorithm ) {
266+ switch (algo . name () ) {
357267 case "HS256" :
358268 case "HS384" :
359269 case "HS512" :
360- this .signingAlgorithm = new MacSigningAlgorithm ( algorithm , mac ) ;
270+ this .signingAlgorithm = algo ;
361271 break ;
362272 default :
363- throw new NoSuchAlgorithmException ("Unknown algorithm: " + algorithm );
273+ throw new NoSuchAlgorithmException ("Unknown algorithm: " + algo . name () );
364274 }
365275 }
366276
367- private JWK (String algorithm , X509Certificate certificate , PrivateKey privateKey ) throws NoSuchAlgorithmException {
277+ private JWK (String algorithm , String id , PubKeySigningAlgorithm algo ) throws NoSuchAlgorithmException {
368278
369279 kid = null ;
370- label = privateKey != null ? algorithm + '#' + certificate . hashCode () + "-" + privateKey .hashCode () : algorithm + '#' + certificate . hashCode () ;
280+ label = algo . canSign () ? algorithm + '#' + id + "-" + algo . privateKey () .hashCode () : algorithm + '#' + id ;
371281 use = null ;
372282
373- PublicKey publicKey = certificate .getPublicKey ();
374-
375- boolean ec ;
376283 switch (algorithm ) {
377284 case "RS256" :
378285 case "RS384" :
379286 case "RS512" :
380287 kty = "RSA" ;
381- ec = false ;
288+ signingAlgorithm = algo ;
382289 break ;
383290 case "PS256" :
384291 case "PS384" :
385292 case "PS512" :
386293 kty = "RSASSA" ;
387- ec = false ;
294+ signingAlgorithm = algo ;
388295 break ;
389296 case "ES256" :
390297 case "ES384" :
391298 case "ES512" :
392299 case "ES256K" :
393300 kty = "EC" ;
394- ec = true ;
301+ signingAlgorithm = wrapECAlgo ( algo ) ;
395302 break ;
396303 default :
397304 throw new NoSuchAlgorithmException ("Unknown algorithm: " + algorithm );
398305 }
399- PubKeySigningAlgorithm algo = createPubKeySigningAlgorithm (algorithm , privateKey , publicKey );
400- if (ec ) {
401- signingAlgorithm = wrapECAlgo (algo );
402- } else {
403- signingAlgorithm = algo ;
404- }
405306 }
406307
407308 private static SigningAlgorithm wrapECAlgo (PubKeySigningAlgorithm signingAlgo ) {
@@ -414,6 +315,10 @@ public String name() {
414315 return signingAlgo .name ();
415316 }
416317 @ Override
318+ public String id () {
319+ return signingAlgo .id ();
320+ }
321+ @ Override
417322 public boolean canSign () {
418323 return signingAlgo .canSign ();
419324 }
@@ -422,8 +327,8 @@ public boolean canVerify() {
422327 return signingAlgo .canVerify ();
423328 }
424329 @ Override
425- public Signer signer () throws GeneralSecurityException {
426- Signer signer = signingAlgo .signer ();
330+ public io . vertx . ext . auth . impl . jose . algo . Signer signer () throws GeneralSecurityException {
331+ io . vertx . ext . auth . impl . jose . algo . Signer signer = signingAlgo .signer ();
427332 int len = getSignatureLength (signingAlgo .name (), signingAlgo .publicKey ());
428333 return new Signer () {
429334 @ Override
@@ -442,10 +347,6 @@ public boolean verify(byte[] expected, byte[] payload) throws GeneralSecurityExc
442347 };
443348 }
444349
445- private static PubKeySigningAlgorithm createPubKeySigningAlgorithm (String alg , PrivateKey privateKey , PublicKey publicKey ) {
446- return new PubKeySigningAlgorithm (alg , privateKey , publicKey );
447- }
448-
449350 public JWK (JsonObject json ) {
450351 kid = json .getString ("kid" );
451352 use = json .getString ("use" );
@@ -568,7 +469,7 @@ private static PubKeySigningAlgorithm createRSA(String alg, JsonObject json) thr
568469 }
569470
570471 if (publicKey != null || privateKey != null ) {
571- return createPubKeySigningAlgorithm (alg , privateKey , publicKey );
472+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , privateKey , publicKey );
572473 }
573474 return null ;
574475 }
@@ -593,7 +494,7 @@ private static PubKeySigningAlgorithm createEC(String alg, JsonObject json) thro
593494 }
594495
595496 if (publicKey != null || privateKey != null ) {
596- return createPubKeySigningAlgorithm (alg , privateKey , publicKey );
497+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , privateKey , publicKey );
597498 }
598499
599500 return null ;
@@ -667,7 +568,7 @@ private static PubKeySigningAlgorithm createOKP(String alg, JsonObject json) thr
667568 }
668569
669570 if (publicKey != null || privateKey != null ) {
670- return createPubKeySigningAlgorithm (alg , privateKey , publicKey );
571+ return PubKeySigningAlgorithm . createPubKeySigningAlgorithm (alg , privateKey , publicKey );
671572 } else {
672573 return null ;
673574 }
0 commit comments