0N/A/*
3909N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.ssl;
0N/A
0N/Aimport javax.net.ssl.*;
0N/Aimport java.security.*;
0N/Aimport java.security.cert.*;
0N/Aimport java.security.cert.Certificate;
0N/Aimport java.util.*;
0N/Aimport java.net.Socket;
0N/A
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/A
0N/A/**
0N/A * An implemention of X509KeyManager backed by a KeyStore.
0N/A *
0N/A * The backing KeyStore is inspected when this object is constructed.
0N/A * All key entries containing a PrivateKey and a non-empty chain of
0N/A * X509Certificate are then copied into an internal store. This means
0N/A * that subsequent modifications of the KeyStore have no effect on the
0N/A * X509KeyManagerImpl object.
0N/A *
0N/A * Note that this class assumes that all keys are protected by the same
0N/A * password.
0N/A *
0N/A * The JSSE handshake code currently calls into this class via
0N/A * chooseClientAlias() and chooseServerAlias() to find the certificates to
0N/A * use. As implemented here, both always return the first alias returned by
0N/A * getClientAliases() and getServerAliases(). In turn, these methods are
0N/A * implemented by calling getAliases(), which performs the actual lookup.
0N/A *
0N/A * Note that this class currently implements no checking of the local
0N/A * certificates. In particular, it is *not* guaranteed that:
0N/A * . the certificates are within their validity period and not revoked
0N/A * . the signatures verify
0N/A * . they form a PKIX compliant chain.
0N/A * . the certificate extensions allow the certificate to be used for
0N/A * the desired purpose.
0N/A *
0N/A * Chains that fail any of these criteria will probably be rejected by
0N/A * the remote peer.
0N/A *
0N/A */
0N/Afinal class SunX509KeyManagerImpl extends X509ExtendedKeyManager {
0N/A
0N/A private static final Debug debug = Debug.getInstance("ssl");
0N/A
0N/A private static final String[] STRING0 = new String[0];
0N/A
0N/A /*
0N/A * The credentials from the KeyStore as
0N/A * Map: String(alias) -> X509Credentials(credentials)
0N/A */
0N/A private Map<String,X509Credentials> credentialsMap;
0N/A
0N/A /*
0N/A * Cached server aliases for the case issuers == null.
0N/A * (in the current JSSE implementation, issuers are always null for
0N/A * server certs). See chooseServerAlias() for details.
0N/A *
0N/A * Map: String(keyType) -> String[](alias)
0N/A */
0N/A private Map<String,String[]> serverAliasCache;
0N/A
0N/A /*
0N/A * Basic container for credentials implemented as an inner class.
0N/A */
0N/A private static class X509Credentials {
0N/A PrivateKey privateKey;
0N/A X509Certificate[] certificates;
0N/A private Set<X500Principal> issuerX500Principals;
0N/A
0N/A X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) {
0N/A // assert privateKey and certificates != null
0N/A this.privateKey = privateKey;
0N/A this.certificates = certificates;
0N/A }
0N/A
0N/A synchronized Set<X500Principal> getIssuerX500Principals() {
0N/A // lazy initialization
0N/A if (issuerX500Principals == null) {
0N/A issuerX500Principals = new HashSet<X500Principal>();
0N/A for (int i = 0; i < certificates.length; i++) {
0N/A issuerX500Principals.add(
0N/A certificates[i].getIssuerX500Principal());
0N/A }
0N/A }
0N/A return issuerX500Principals;
0N/A }
0N/A }
0N/A
0N/A SunX509KeyManagerImpl(KeyStore ks, char[] password) throws KeyStoreException,
0N/A NoSuchAlgorithmException, UnrecoverableKeyException {
0N/A
0N/A credentialsMap = new HashMap<String,X509Credentials>();
0N/A serverAliasCache = new HashMap<String,String[]>();
0N/A if (ks == null) {
0N/A return;
0N/A }
0N/A
0N/A for (Enumeration<String> aliases = ks.aliases();
0N/A aliases.hasMoreElements(); ) {
0N/A String alias = aliases.nextElement();
0N/A if (!ks.isKeyEntry(alias)) {
0N/A continue;
0N/A }
0N/A Key key = ks.getKey(alias, password);
0N/A if (key instanceof PrivateKey == false) {
0N/A continue;
0N/A }
0N/A Certificate[] certs = ks.getCertificateChain(alias);
0N/A if ((certs == null) || (certs.length == 0) ||
0N/A !(certs[0] instanceof X509Certificate)) {
0N/A continue;
0N/A }
0N/A if (!(certs instanceof X509Certificate[])) {
0N/A Certificate[] tmp = new X509Certificate[certs.length];
0N/A System.arraycopy(certs, 0, tmp, 0, certs.length);
0N/A certs = tmp;
0N/A }
0N/A
0N/A X509Credentials cred = new X509Credentials((PrivateKey)key,
0N/A (X509Certificate[])certs);
0N/A credentialsMap.put(alias, cred);
0N/A if (debug != null && Debug.isOn("keymanager")) {
0N/A System.out.println("***");
0N/A System.out.println("found key for : " + alias);
0N/A for (int i = 0; i < certs.length; i++) {
0N/A System.out.println("chain [" + i + "] = "
0N/A + certs[i]);
0N/A }
0N/A System.out.println("***");
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns the certificate chain associated with the given alias.
0N/A *
0N/A * @return the certificate chain (ordered with the user's certificate first
0N/A * and the root certificate authority last)
0N/A */
0N/A public X509Certificate[] getCertificateChain(String alias) {
0N/A if (alias == null) {
0N/A return null;
0N/A }
0N/A X509Credentials cred = credentialsMap.get(alias);
0N/A if (cred == null) {
0N/A return null;
0N/A } else {
28N/A return cred.certificates.clone();
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Returns the key associated with the given alias
0N/A */
0N/A public PrivateKey getPrivateKey(String alias) {
0N/A if (alias == null) {
0N/A return null;
0N/A }
0N/A X509Credentials cred = credentialsMap.get(alias);
0N/A if (cred == null) {
0N/A return null;
0N/A } else {
0N/A return cred.privateKey;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Choose an alias to authenticate the client side of a secure
0N/A * socket given the public key type and the list of
0N/A * certificate issuer authorities recognized by the peer (if any).
0N/A */
0N/A public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
0N/A Socket socket) {
0N/A /*
0N/A * We currently don't do anything with socket, but
0N/A * someday we might. It might be a useful hint for
0N/A * selecting one of the aliases we get back from
0N/A * getClientAliases().
0N/A */
0N/A
0N/A if (keyTypes == null) {
0N/A return null;
0N/A }
0N/A
0N/A for (int i = 0; i < keyTypes.length; i++) {
0N/A String[] aliases = getClientAliases(keyTypes[i], issuers);
0N/A if ((aliases != null) && (aliases.length > 0)) {
0N/A return aliases[0];
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /*
0N/A * Choose an alias to authenticate the client side of an
0N/A * <code>SSLEngine</code> connection given the public key type
0N/A * and the list of certificate issuer authorities recognized by
0N/A * the peer (if any).
0N/A *
0N/A * @since 1.5
0N/A */
0N/A public String chooseEngineClientAlias(String[] keyType,
0N/A Principal[] issuers, SSLEngine engine) {
0N/A /*
0N/A * If we ever start using socket as a selection criteria,
0N/A * we'll need to adjust this.
0N/A */
0N/A return chooseClientAlias(keyType, issuers, null);
0N/A }
0N/A
0N/A /*
0N/A * Choose an alias to authenticate the server side of a secure
0N/A * socket given the public key type and the list of
0N/A * certificate issuer authorities recognized by the peer (if any).
0N/A */
0N/A public String chooseServerAlias(String keyType,
0N/A Principal[] issuers, Socket socket) {
0N/A /*
0N/A * We currently don't do anything with socket, but
0N/A * someday we might. It might be a useful hint for
0N/A * selecting one of the aliases we get back from
0N/A * getServerAliases().
0N/A */
0N/A if (keyType == null) {
0N/A return null;
0N/A }
0N/A
0N/A String[] aliases;
0N/A
0N/A if (issuers == null || issuers.length == 0) {
28N/A aliases = serverAliasCache.get(keyType);
0N/A if (aliases == null) {
0N/A aliases = getServerAliases(keyType, issuers);
0N/A // Cache the result (positive and negative lookups)
0N/A if (aliases == null) {
0N/A aliases = STRING0;
0N/A }
0N/A serverAliasCache.put(keyType, aliases);
0N/A }
0N/A } else {
0N/A aliases = getServerAliases(keyType, issuers);
0N/A }
0N/A if ((aliases != null) && (aliases.length > 0)) {
0N/A return aliases[0];
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /*
0N/A * Choose an alias to authenticate the server side of an
0N/A * <code>SSLEngine</code> connection given the public key type
0N/A * and the list of certificate issuer authorities recognized by
0N/A * the peer (if any).
0N/A *
0N/A * @since 1.5
0N/A */
0N/A public String chooseEngineServerAlias(String keyType,
0N/A Principal[] issuers, SSLEngine engine) {
0N/A /*
0N/A * If we ever start using socket as a selection criteria,
0N/A * we'll need to adjust this.
0N/A */
0N/A return chooseServerAlias(keyType, issuers, null);
0N/A }
0N/A
0N/A /*
0N/A * Get the matching aliases for authenticating the client side of a secure
0N/A * socket given the public key type and the list of
0N/A * certificate issuer authorities recognized by the peer (if any).
0N/A */
0N/A public String[] getClientAliases(String keyType, Principal[] issuers) {
0N/A return getAliases(keyType, issuers);
0N/A }
0N/A
0N/A /*
0N/A * Get the matching aliases for authenticating the server side of a secure
0N/A * socket given the public key type and the list of
0N/A * certificate issuer authorities recognized by the peer (if any).
0N/A */
0N/A public String[] getServerAliases(String keyType, Principal[] issuers) {
0N/A return getAliases(keyType, issuers);
0N/A }
0N/A
0N/A /*
0N/A * Get the matching aliases for authenticating the either side of a secure
0N/A * socket given the public key type and the list of
0N/A * certificate issuer authorities recognized by the peer (if any).
0N/A *
0N/A * Issuers comes to us in the form of X500Principal[].
0N/A */
0N/A private String[] getAliases(String keyType, Principal[] issuers) {
0N/A if (keyType == null) {
0N/A return null;
0N/A }
0N/A if (issuers == null) {
0N/A issuers = new X500Principal[0];
0N/A }
0N/A if (issuers instanceof X500Principal[] == false) {
0N/A // normally, this will never happen but try to recover if it does
0N/A issuers = convertPrincipals(issuers);
0N/A }
0N/A String sigType;
0N/A if (keyType.contains("_")) {
0N/A int k = keyType.indexOf("_");
0N/A sigType = keyType.substring(k + 1);
0N/A keyType = keyType.substring(0, k);
0N/A } else {
0N/A sigType = null;
0N/A }
0N/A
0N/A X500Principal[] x500Issuers = (X500Principal[])issuers;
0N/A // the algorithm below does not produce duplicates, so avoid Set
3401N/A List<String> aliases = new ArrayList<>();
0N/A
0N/A for (Map.Entry<String,X509Credentials> entry :
0N/A credentialsMap.entrySet()) {
0N/A
0N/A String alias = entry.getKey();
0N/A X509Credentials credentials = entry.getValue();
0N/A X509Certificate[] certs = credentials.certificates;
0N/A
0N/A if (!keyType.equals(certs[0].getPublicKey().getAlgorithm())) {
0N/A continue;
0N/A }
0N/A if (sigType != null) {
0N/A if (certs.length > 1) {
0N/A // if possible, check the public key in the issuer cert
0N/A if (!sigType.equals(certs[1].getPublicKey().getAlgorithm())) {
0N/A continue;
0N/A }
0N/A } else {
0N/A // Check the signature algorithm of the certificate itself.
0N/A // Look for the "withRSA" in "SHA1withRSA", etc.
0N/A String sigAlgName =
0N/A certs[0].getSigAlgName().toUpperCase(Locale.ENGLISH);
0N/A String pattern = "WITH" + sigType.toUpperCase(Locale.ENGLISH);
0N/A if (sigAlgName.contains(pattern) == false) {
0N/A continue;
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (issuers.length == 0) {
0N/A // no issuer specified, match all
0N/A aliases.add(alias);
0N/A if (debug != null && Debug.isOn("keymanager")) {
0N/A System.out.println("matching alias: " + alias);
0N/A }
0N/A } else {
0N/A Set<X500Principal> certIssuers =
0N/A credentials.getIssuerX500Principals();
0N/A for (int i = 0; i < x500Issuers.length; i++) {
0N/A if (certIssuers.contains(issuers[i])) {
0N/A aliases.add(alias);
0N/A if (debug != null && Debug.isOn("keymanager")) {
0N/A System.out.println("matching alias: " + alias);
0N/A }
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
28N/A String[] aliasStrings = aliases.toArray(STRING0);
0N/A return ((aliasStrings.length == 0) ? null : aliasStrings);
0N/A }
0N/A
0N/A /*
0N/A * Convert an array of Principals to an array of X500Principals, if
0N/A * possible. Principals that cannot be converted are ignored.
0N/A */
0N/A private static X500Principal[] convertPrincipals(Principal[] principals) {
3401N/A List<X500Principal> list = new ArrayList<>(principals.length);
0N/A for (int i = 0; i < principals.length; i++) {
0N/A Principal p = principals[i];
0N/A if (p instanceof X500Principal) {
0N/A list.add((X500Principal)p);
0N/A } else {
0N/A try {
0N/A list.add(new X500Principal(p.getName()));
0N/A } catch (IllegalArgumentException e) {
0N/A // ignore
0N/A }
0N/A }
0N/A }
0N/A return list.toArray(new X500Principal[list.size()]);
0N/A }
0N/A
0N/A}