1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.json.jose.jwk;
18
19 import java.math.BigInteger;
20 import java.security.KeyFactory;
21 import java.security.KeyPair;
22 import java.security.interfaces.RSAPrivateCrtKey;
23 import java.security.interfaces.RSAPrivateKey;
24 import java.security.interfaces.RSAPublicKey;
25 import java.security.spec.RSAMultiPrimePrivateCrtKeySpec;
26 import java.security.spec.RSAOtherPrimeInfo;
27 import java.security.spec.RSAPrivateCrtKeySpec;
28 import java.security.spec.RSAPrivateKeySpec;
29 import java.security.spec.RSAPublicKeySpec;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
34
35 import org.forgerock.json.JsonException;
36 import org.forgerock.json.JsonValue;
37 import org.forgerock.util.encode.Base64url;
38
39
40
41
42 public class RsaJWK extends JWK {
43
44 private static final int BIG_INTEGER_POSITIVE = 1;
45
46
47
48
49 public static class OtherFactors extends JsonValue {
50
51
52
53 private final static String R = "r";
54
55
56
57
58 private final static String D = "d";
59
60
61
62
63 private final static String T = "t";
64
65
66
67
68
69
70
71 public OtherFactors(String r, String d, String t) {
72 super(new HashMap<>());
73 put(R, r);
74 put(D, d);
75 put(T, t);
76 }
77
78
79
80
81
82 public OtherFactors(RSAOtherPrimeInfo info) {
83 super(new HashMap<>());
84 put(R, Base64url.encode(info.getPrime().toByteArray()));
85 put(D, Base64url.encode(info.getExponent().toByteArray()));
86 put(T, Base64url.encode(info.getCrtCoefficient().toByteArray()));
87 }
88
89
90
91
92
93 public String getFactor() {
94 return get(R).asString();
95 }
96
97
98
99
100
101 public String getCRTExponent() {
102 return get(D).asString();
103 }
104
105
106
107
108
109 public String getCRTCoefficient() {
110 return get(T).asString();
111 }
112 }
113
114
115
116
117 private final static String N = "n";
118
119
120
121
122 private final static String E = "e";
123
124
125
126
127 private final static String D = "d";
128
129
130
131
132 private final static String P = "p";
133
134
135
136
137 private final static String Q = "q";
138
139
140
141
142 private final static String DP = "dp";
143
144
145
146
147 private final static String DQ = "dq";
148
149
150
151
152 private final static String QI = "qi";
153
154
155
156
157 private final static String FACTORS = "factors";
158
159
160
161
162
163
164
165
166
167
168
169
170 public RsaJWK(KeyUse use, String alg, String kid, String n, String e, String x5u, String x5t, List<String> x5c) {
171 this (use, alg, kid, n, e, null, null, null, null, null, null, null, x5u, x5t, x5c);
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public RsaJWK(KeyUse use, String alg, String kid, String n, String e, String d, String x5u, String x5t,
187 List<String> x5c) {
188 this (use, alg, kid, n, e, d, null, null, null, null, null, null, x5u, x5t, x5c);
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 public RsaJWK(KeyUse use, String alg, String kid, String n, String e, String p, String q, String dp,
208 String dq, String qi, String x5u, String x5t, List<String> x5c) {
209 this (use, alg, kid, n, e, null, p, q, dp, dq, qi, null, x5u, x5t, x5c);
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 public RsaJWK(KeyUse use, String alg, String kid, String n, String e, String d, String p, String q,
231 String dp, String dq, String qi, List<OtherFactors> factors,
232 String x5u, String x5t, List<String> x5c) {
233 super(KeyType.RSA, use, alg, kid, x5u, x5t, x5c);
234 if (n != null && !n.isEmpty()) {
235 put(N, n);
236 }
237 if (e != null && !e.isEmpty()) {
238 put(E, e);
239 }
240 if (d != null && !d.isEmpty()) {
241 put(D, d);
242 }
243 if (p != null && !p.isEmpty()) {
244 put(P, p);
245 }
246 if (q != null && !q.isEmpty()) {
247 put(Q, q);
248 }
249 if (dp != null && !dp.isEmpty()) {
250 put(DP, dp);
251 }
252 if (dq != null && !dq.isEmpty()) {
253 put(DQ, dq);
254 }
255 if (qi != null && !qi.isEmpty()) {
256 put(QI, qi);
257 }
258 if (factors == null) {
259 put(FACTORS, Collections.EMPTY_LIST);
260 } else {
261 put(FACTORS, factors);
262 }
263 if (x5u != null && !x5u.isEmpty()) {
264 put(X5U, x5u);
265 }
266 if (x5t != null && !x5t.isEmpty()) {
267 put(X5T, x5t);
268 }
269 if (x5c != null && !x5c.isEmpty()) {
270 put(X5C, x5c);
271 }
272
273
274 }
275
276
277
278
279
280
281
282
283
284
285
286 public RsaJWK(RSAPublicKey key, KeyUse use, String alg, String kid, String x5u, String x5t, List<String> x5c) {
287 this(use, alg, kid,
288 Base64url.encode(key.getModulus().toByteArray()),
289 Base64url.encode(key.getPublicExponent().toByteArray()),
290 x5u, x5t, x5c);
291 }
292
293
294
295
296
297
298
299
300
301
302
303 public RsaJWK(RSAPublicKey pubKey, RSAPrivateKey privKey, KeyUse use, String alg, String kid,
304 String x5u, String x5t, List<String> x5c) {
305 this(use, alg, kid,
306 Base64url.encode(pubKey.getModulus().toByteArray()),
307 Base64url.encode(pubKey.getPublicExponent().toByteArray()),
308 Base64url.encode(privKey.getPrivateExponent().toByteArray()),
309 x5u, x5t, x5c);
310 }
311
312
313
314
315
316
317
318
319
320
321
322 public RsaJWK(RSAPublicKey pubKey, RSAPrivateCrtKey privCert, KeyUse use, String alg, String kid,
323 String x5u, String x5t, List<String> x5c) {
324 this(use, alg, kid,
325 Base64url.encode(pubKey.getModulus().toByteArray()),
326 Base64url.encode(pubKey.getPublicExponent().toByteArray()),
327 Base64url.encode(privCert.getPrivateExponent().toByteArray()),
328 Base64url.encode(privCert.getPrimeP().toByteArray()),
329 Base64url.encode(privCert.getPrimeQ().toByteArray()),
330 Base64url.encode(privCert.getPrimeExponentP().toByteArray()),
331 Base64url.encode(privCert.getPrimeExponentQ().toByteArray()),
332 Base64url.encode(privCert.getCrtCoefficient().toByteArray()),
333 null, x5u, x5t, x5c);
334
335 }
336
337
338
339
340
341 public String getModulus() {
342 return get(N).asString();
343 }
344
345
346
347
348
349 public String getPublicExponent() {
350 return get(E).asString();
351 }
352
353
354
355
356
357 public String getPrivateExponent() {
358 return get(D).asString();
359 }
360
361
362
363
364
365 public String getPrimeP() {
366 return get(P).asString();
367 }
368
369
370
371
372
373 public String getPrimeQ() {
374 return get(Q).asString();
375 }
376
377
378
379
380
381 public String getPrimePExponent() {
382 return get(DP).asString();
383 }
384
385
386
387
388
389 public String getPrimeQExponent() {
390 return get(DQ).asString();
391 }
392
393
394
395
396
397 public String getCRTCoefficient() {
398 return get(QI).asString();
399 }
400
401
402
403
404
405 public List<Object> getOtherFactors() {
406 return get(FACTORS).asList();
407 }
408
409
410
411
412
413 public RSAPublicKey toRSAPublicKey() {
414 try {
415 RSAPublicKeySpec spec = new RSAPublicKeySpec(asPositiveBigInteger(getModulus()),
416 asPositiveBigInteger(getPublicExponent()));
417 KeyFactory factory = KeyFactory.getInstance("RSA");
418 return (RSAPublicKey) factory.generatePublic(spec);
419 } catch (Exception e) {
420 throw new JsonException("Unable to create RSA Public Key", e);
421 }
422 }
423
424
425
426
427
428 public RSAPrivateKey toRSAPrivateKey() {
429
430 if (getPrivateExponent() == null) {
431 return null;
432 }
433
434 BigInteger modulus = asPositiveBigInteger(getModulus());
435 BigInteger privateExponent = asPositiveBigInteger(getPrivateExponent());
436
437 RSAPrivateKeySpec spec;
438
439 if (getPrimeP() == null) {
440
441 spec = new RSAPrivateKeySpec(modulus, privateExponent);
442
443 } else {
444
445 BigInteger publicExponent = asPositiveBigInteger(getPublicExponent());
446 BigInteger p = asPositiveBigInteger(getPrimeP());
447 BigInteger q = asPositiveBigInteger(getPrimeQ());
448 BigInteger dp = asPositiveBigInteger(getPrimePExponent());
449 BigInteger dq = asPositiveBigInteger(getPrimeQExponent());
450 BigInteger qi = asPositiveBigInteger(getCRTCoefficient());
451
452 if (getOtherFactors() != null && !getOtherFactors().isEmpty()) {
453
454 RSAOtherPrimeInfo[] otherInfo = new RSAOtherPrimeInfo[getOtherFactors().size()];
455
456 for (int i = 0; i < getOtherFactors().size(); i++) {
457
458 OtherFactors factor = (OtherFactors) getOtherFactors().get(i);
459
460 BigInteger factorR = asPositiveBigInteger(factor.getFactor());
461 BigInteger factorD = asPositiveBigInteger(factor.getCRTExponent());
462 BigInteger factorT = asPositiveBigInteger(factor.getCRTCoefficient());
463
464 otherInfo[i] = new RSAOtherPrimeInfo(factorR, factorD, factorT);
465 }
466
467 spec = new RSAMultiPrimePrivateCrtKeySpec(modulus, publicExponent, privateExponent, p, q, dp, dq, qi,
468 otherInfo);
469 } else {
470 spec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, p, q, dp, dq, qi);
471 }
472 }
473
474 try {
475 KeyFactory factory = KeyFactory.getInstance("RSA");
476 RSAPrivateKey priv = (RSAPrivateKey) factory.generatePrivate(spec);
477 return priv;
478 } catch (Exception e) {
479 throw new JsonException("Unable to create private RSA Key", e);
480 }
481 }
482
483
484
485
486
487 public KeyPair toKeyPair() {
488 return new KeyPair(toRSAPublicKey(), toRSAPrivateKey());
489 }
490
491
492
493
494
495
496 public static RsaJWK parse(String json) {
497 JsonValue jwk = new JsonValue(toJsonValue(json));
498 return parse(jwk);
499 }
500
501
502
503
504
505
506 public static RsaJWK parse(JsonValue json) {
507
508 String n = null, e = null, d = null, p = null, q = null, dq = null, dp = null, qi = null;
509 String x5u = null, x5t = null;
510 List<String> x5c = null;
511 List<Object> factors = null;
512 List<OtherFactors> listOfFactors = null;
513
514 KeyType kty = null;
515 KeyUse use = null;
516 String alg = null, kid = null;
517
518 kty = KeyType.getKeyType(json.get(KTY).asString());
519 if (!kty.equals(KeyType.RSA)) {
520 throw new JsonException("Unable to parse RSA JWK; Not an RSA type");
521 }
522
523 use = KeyUse.getKeyUse(json.get(USE).asString());
524 alg = json.get(ALG).asString();
525 kid = json.get(KID).asString();
526
527 n = json.get(N).asString();
528 e = json.get(E).asString();
529 d = json.get(D).asString();
530 p = json.get(P).asString();
531 q = json.get(Q).asString();
532 dp = json.get(DP).asString();
533 dq = json.get(DQ).asString();
534 qi = json.get(QI).asString();
535 factors = json.get(FACTORS).asList();
536 x5u = json.get(X5U).asString();
537 x5t = json.get(X5T).asString();
538 x5c = json.get(X5C).asList(String.class);
539 if (factors != null && !factors.isEmpty()) {
540 listOfFactors = new ArrayList<>(factors.size());
541 for (Object factor : factors) {
542 String r = null, dd = null, t = null;
543 r = ((JsonValue) factor).get("r").asString();
544 dd = ((JsonValue) factor).get("d").asString();
545 t = ((JsonValue) factor).get("t").asString();
546 OtherFactors of = new OtherFactors(r, dd, t);
547 listOfFactors.add(of);
548 }
549 }
550
551 return new RsaJWK(use, alg, kid, n, e, d, p, q, dp, dq, qi, listOfFactors, x5u, x5t, x5c);
552 }
553
554
555
556
557
558 public String toJsonString() {
559 return super.toString();
560 }
561
562
563
564
565
566 private BigInteger asPositiveBigInteger(String toConvert) {
567 return new BigInteger(BIG_INTEGER_POSITIVE, Base64url.decode(toConvert));
568 }
569 }