|
4 | 4 | import java.util.Collection; |
5 | 5 | import java.util.EventListener; |
6 | 6 | import java.util.HashMap; |
| 7 | +import java.util.List; |
7 | 8 | import java.util.concurrent.atomic.AtomicBoolean; |
8 | 9 |
|
9 | 10 | import javax.net.ssl.SSLEngineResult; |
10 | 11 | import javax.net.ssl.SSLException; |
11 | 12 | import javax.net.ssl.SSLParameters; |
12 | 13 | import javax.net.ssl.X509KeyManager; |
13 | 14 | import javax.net.ssl.X509TrustManager; |
| 15 | +import org.apache.commons.lang3.tuple.ImmutablePair; |
| 16 | +import org.apache.commons.lang3.tuple.Pair; |
14 | 17 |
|
15 | 18 | import org.mozilla.jss.crypto.Policy; |
16 | 19 | import org.mozilla.jss.nss.PR; |
@@ -76,21 +79,16 @@ public abstract class JSSEngine extends javax.net.ssl.SSLEngine { |
76 | 79 | /** |
77 | 80 | * Certificate alias used by the JSSEngine instance. |
78 | 81 | */ |
79 | | - protected String certAlias; |
| 82 | + protected List<String> certAliases; |
80 | 83 |
|
81 | 84 | /** |
82 | | - * Certificate used by this JSSEngine instance. |
| 85 | + * Collection of certificates and related keys used by this JSSEngine instance. |
83 | 86 | * |
84 | 87 | * Selected and inferred from the KeyManagers passed, when not passed |
85 | 88 | * explicitly (either during construction or with a call to |
86 | 89 | * setKeyMaterials(...)). |
87 | 90 | */ |
88 | | - protected PK11Cert cert; |
89 | | - |
90 | | - /** |
91 | | - * Key corresponding to the local certificate. |
92 | | - */ |
93 | | - protected PK11PrivKey key; |
| 91 | + protected List<Pair<PK11Cert, PK11PrivKey>> certs; |
94 | 92 |
|
95 | 93 | /** |
96 | 94 | * A list of all KeyManagers available to this JSSEngine instance. |
@@ -197,7 +195,7 @@ public abstract class JSSEngine extends javax.net.ssl.SSLEngine { |
197 | 195 | * Set of cached server sockets based on the PK11Cert they were |
198 | 196 | * initialized with. |
199 | 197 | */ |
200 | | - protected static HashMap<PK11Cert, SSLFDProxy> serverTemplates = new HashMap<>(); |
| 198 | + protected static HashMap<List<Pair<PK11Cert, PK11PrivKey>>, SSLFDProxy> serverTemplates = new HashMap<>(); |
201 | 199 |
|
202 | 200 | /** |
203 | 201 | * Whether or not the session cache has been initialized already. |
@@ -255,9 +253,8 @@ public JSSEngine(String peerHost, int peerPort, |
255 | 253 | org.mozilla.jss.crypto.X509Certificate localCert, |
256 | 254 | org.mozilla.jss.crypto.PrivateKey localKey) { |
257 | 255 | super(peerHost, peerPort); |
258 | | - |
259 | | - cert = (PK11Cert) localCert; |
260 | | - key = (PK11PrivKey) localKey; |
| 256 | + certs = new ArrayList<>(); |
| 257 | + certs.add(ImmutablePair.of((PK11Cert) localCert, (PK11PrivKey) localKey)); |
261 | 258 |
|
262 | 259 | session = new JSSSession(this, BUFFER_SIZE); |
263 | 260 | session.setPeerHost(peerHost); |
@@ -338,7 +335,7 @@ public JSSParameters getSSLParameters() { |
338 | 335 | ret.setWantClientAuth(true); |
339 | 336 | } |
340 | 337 |
|
341 | | - ret.setAlias(certAlias); |
| 338 | + ret.setAliases(certAliases); |
342 | 339 | ret.setHostname(hostname); |
343 | 340 | ret.setListeners(listeners); |
344 | 341 |
|
@@ -405,8 +402,9 @@ public void setSSLParameters(SSLParameters params) { |
405 | 402 | // them from the alias specified... We assume that when the SSLEngine |
406 | 403 | // has a certificate already, we want to use them, even if parsed has |
407 | 404 | // a null certificate. |
408 | | - if (parsed.getAlias() != null && key_managers != null && key_managers.length > 0 && cert == null && key == null) { |
409 | | - setCertFromAlias(parsed.getAlias()); |
| 405 | + if (parsed.getAliases() != null && !parsed.getAliases().isEmpty() && key_managers != null && key_managers.length > 0 |
| 406 | + && (certs == null || certs.isEmpty())) { |
| 407 | + setCertFromAliases(parsed.getAliases()); |
410 | 408 | } |
411 | 409 |
|
412 | 410 | // When we have a value for the peer hostname, we should try and use |
@@ -452,54 +450,64 @@ public void setHostname(String name) { |
452 | 450 | * |
453 | 451 | */ |
454 | 452 | public void setCertFromAlias(String alias) throws IllegalArgumentException { |
455 | | - if (alias == null) { |
| 453 | + List<String> aliases = new ArrayList<>(); |
| 454 | + if (alias != null) { |
| 455 | + aliases.add(alias); |
| 456 | + } |
| 457 | + setCertFromAliases(aliases); |
| 458 | + } |
| 459 | + |
| 460 | + public void setCertFromAliases(List<String> aliases) throws IllegalArgumentException { |
| 461 | + if (aliases == null || aliases.isEmpty()) { |
456 | 462 | // Per calling, semantics, get rid of any existing cert/key we |
457 | 463 | // might have. |
458 | | - certAlias = null; |
459 | | - cert = null; |
460 | | - key = null; |
| 464 | + certAliases = null; |
| 465 | + certs = null; |
461 | 466 | return; |
462 | 467 | } |
463 | 468 |
|
464 | | - certAlias = alias; |
| 469 | + certAliases = aliases; |
| 470 | + certs = new ArrayList<>(); |
465 | 471 |
|
466 | 472 | if (key_managers == null || key_managers.length == 0) { |
467 | 473 | String msg = "Missing or null KeyManagers; refusing to search "; |
468 | 474 | msg += "for cert"; |
469 | 475 | throw new IllegalArgumentException(msg); |
470 | 476 | } |
471 | 477 |
|
472 | | - for (X509KeyManager key_manager : key_managers) { |
473 | | - if (key_manager == null) { |
474 | | - // Skip this key_manager. This case could occur when |
475 | | - // setKeyManagers(...) is passed an array containing the value |
476 | | - // null, but otherwise shouldn't happen. |
477 | | - continue; |
478 | | - } |
| 478 | + for (String alias: certAliases) { |
| 479 | + for (X509KeyManager key_manager : key_managers) { |
| 480 | + if (key_manager == null) { |
| 481 | + // Skip this key_manager. This case could occur when |
| 482 | + // setKeyManagers(...) is passed an array containing the value |
| 483 | + // null, but otherwise shouldn't happen. |
| 484 | + continue; |
| 485 | + } |
479 | 486 |
|
480 | | - if (!(key_manager instanceof JSSKeyManager)) { |
481 | | - // We're explicitly looking for a JSSKeyManager; skip this if |
482 | | - // it doesn't match. |
483 | | - continue; |
484 | | - } |
| 487 | + if (!(key_manager instanceof JSSKeyManager)) { |
| 488 | + // We're explicitly looking for a JSSKeyManager; skip this if |
| 489 | + // it doesn't match. |
| 490 | + continue; |
| 491 | + } |
485 | 492 |
|
486 | | - JSSKeyManager jkm = (JSSKeyManager) key_manager; |
| 493 | + JSSKeyManager jkm = (JSSKeyManager) key_manager; |
487 | 494 |
|
488 | | - // While the return type of CryptoManager.findCertByNickname is |
489 | | - // technically org.mozilla.jss.crypto.X509Certificate, in practice |
490 | | - // they are always PK11Cert instances. We're going to need an |
491 | | - // instance of PK11Cert anyways, in order to correctly pass it to |
492 | | - // the native layer. |
493 | | - cert = (PK11Cert) jkm.getCertificate(alias); |
494 | | - key = (PK11PrivKey) jkm.getPrivateKey(alias); |
| 495 | + // While the return type of CryptoManager.findCertByNickname is |
| 496 | + // technically org.mozilla.jss.crypto.X509Certificate, in practice |
| 497 | + // they are always PK11Cert instances. We're going to need an |
| 498 | + // instance of PK11Cert anyways, in order to correctly pass it to |
| 499 | + // the native layer. |
| 500 | + PK11Cert cert = (PK11Cert) jkm.getCertificate(alias); |
| 501 | + PK11PrivKey key = (PK11PrivKey) jkm.getPrivateKey(alias); |
495 | 502 |
|
496 | | - if (cert != null && key != null) { |
497 | | - // Found a cert and key matching our alias; exit. |
498 | | - break; |
| 503 | + if (cert != null && key != null) { |
| 504 | + // Found a cert and key matching our alias; exit. |
| 505 | + certs.add(ImmutablePair.of(cert, key)); |
| 506 | + break; |
| 507 | + } |
499 | 508 | } |
500 | 509 | } |
501 | | - |
502 | | - if (cert == null && key == null) { |
| 510 | + if (certs.isEmpty()) { |
503 | 511 | String msg = "JSSEngine.setCertFromAlias: Unable to find "; |
504 | 512 | msg += "certificate and key for specified alias!"; |
505 | 513 | throw new IllegalArgumentException(msg); |
@@ -771,8 +779,10 @@ public void setKeyMaterials(PK11Cert our_cert, PK11PrivKey our_key) throws Illeg |
771 | 779 | throw new IllegalArgumentException("JSSEngine.setKeyMaterials(): Either both cert and key must be null or both must be not-null"); |
772 | 780 | } |
773 | 781 |
|
774 | | - cert = our_cert; |
775 | | - key = our_key; |
| 782 | + if (certs == null) { |
| 783 | + certs = new ArrayList<>(); |
| 784 | + } |
| 785 | + certs.add(ImmutablePair.of(our_cert, our_key)); |
776 | 786 | } |
777 | 787 |
|
778 | 788 | /** |
@@ -1093,23 +1103,25 @@ public void setConfiguration(HashMap<Integer, Integer> config) { |
1093 | 1103 | /** |
1094 | 1104 | * Returns the templated server certificate, if one exists. |
1095 | 1105 | */ |
1096 | | - protected static SSLFDProxy getServerTemplate(PK11Cert cert, PK11PrivKey key) { |
1097 | | - if (cert == null || key == null) { |
| 1106 | + protected static SSLFDProxy getServerTemplate(List<Pair<PK11Cert, PK11PrivKey>> lstCerts) { |
| 1107 | + if (lstCerts == null || lstCerts.isEmpty()) { |
1098 | 1108 | return null; |
1099 | 1109 | } |
1100 | 1110 |
|
1101 | | - SSLFDProxy fd = serverTemplates.get(cert); |
| 1111 | + SSLFDProxy fd = serverTemplates.get(lstCerts); |
1102 | 1112 | if (fd == null) { |
1103 | 1113 | PRFDProxy base = PR.NewTCPSocket(); |
1104 | 1114 | fd = SSL.ImportFD(null, base); |
1105 | | - if (SSL.ConfigServerCert(fd, cert, key) != SSL.SECSuccess) { |
1106 | | - String msg = "Unable to configure certificate and key on "; |
1107 | | - msg += "model SSL PRFileDesc proxy: "; |
1108 | | - msg += errorText(PR.GetError()); |
1109 | | - throw new RuntimeException(msg); |
| 1115 | + for(Pair<PK11Cert, PK11PrivKey> pairKey: lstCerts) { |
| 1116 | + if (SSL.ConfigServerCert(fd, pairKey.getLeft(), pairKey.getRight()) != SSL.SECSuccess) { |
| 1117 | + String msg = "Unable to configure certificate and key on "; |
| 1118 | + msg += "model SSL PRFileDesc proxy: "; |
| 1119 | + msg += errorText(PR.GetError()); |
| 1120 | + throw new RuntimeException(msg); |
| 1121 | + } |
1110 | 1122 | } |
1111 | | - |
1112 | | - serverTemplates.put(cert, fd); |
| 1123 | + |
| 1124 | + serverTemplates.put(lstCerts, fd); |
1113 | 1125 | } |
1114 | 1126 |
|
1115 | 1127 | return fd; |
|
0 commit comments