X509KeyManagerImpl.java 33.3 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
 */

package sun.security.ssl;

import java.lang.ref.*;
import java.util.*;
import static java.util.Locale.ENGLISH;
import java.util.concurrent.atomic.AtomicLong;
import java.net.Socket;

import java.security.*;
import java.security.KeyStore.*;
import java.security.cert.*;
import java.security.cert.Certificate;

import javax.net.ssl.*;

X
xuelei 已提交
41
import sun.security.provider.certpath.AlgorithmChecker;
42
import sun.security.validator.Validator;
X
xuelei 已提交
43

D
duke 已提交
44 45 46 47 48 49 50 51
/**
 * The new X509 key manager implementation. The main differences to the
 * old SunX509 key manager are:
 *  . it is based around the KeyStore.Builder API. This allows it to use
 *    other forms of KeyStore protection or password input (e.g. a
 *    CallbackHandler) or to have keys within one KeyStore protected by
 *    different keys.
 *  . it can use multiple KeyStores at the same time.
52
 *  . it is explicitly designed to accommodate KeyStores that change over
D
duke 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65
 *    the lifetime of the process.
 *  . it makes an effort to choose the key that matches best, i.e. one that
 *    is not expired and has the appropriate certificate extensions.
 *
 * Note that this code is not explicitly performance optimzied yet.
 *
 * @author  Andreas Sterbenz
 */
final class X509KeyManagerImpl extends X509ExtendedKeyManager
        implements X509KeyManager {

    private static final Debug debug = Debug.getInstance("ssl");

66
    private static final boolean useDebug =
D
duke 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
                            (debug != null) && Debug.isOn("keymanager");

    // for unit testing only, set via privileged reflection
    private static Date verificationDate;

    // list of the builders
    private final List<Builder> builders;

    // counter to generate unique ids for the aliases
    private final AtomicLong uidCounter;

    // cached entries
    private final Map<String,Reference<PrivateKeyEntry>> entryCacheMap;

    X509KeyManagerImpl(Builder builder) {
        this(Collections.singletonList(builder));
    }

    X509KeyManagerImpl(List<Builder> builders) {
        this.builders = builders;
        uidCounter = new AtomicLong();
        entryCacheMap = Collections.synchronizedMap
                        (new SizedMap<String,Reference<PrivateKeyEntry>>());
    }

    // LinkedHashMap with a max size of 10
    // see LinkedHashMap JavaDocs
    private static class SizedMap<K,V> extends LinkedHashMap<K,V> {
95 96
        private static final long serialVersionUID = -8211222668790986062L;

D
duke 已提交
97 98 99 100 101 102 103 104 105
        @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return size() > 10;
        }
    }

    //
    // public methods
    //

106
    @Override
D
duke 已提交
107 108 109 110 111 112
    public X509Certificate[] getCertificateChain(String alias) {
        PrivateKeyEntry entry = getEntry(alias);
        return entry == null ? null :
                (X509Certificate[])entry.getCertificateChain();
    }

113
    @Override
D
duke 已提交
114 115 116 117 118
    public PrivateKey getPrivateKey(String alias) {
        PrivateKeyEntry entry = getEntry(alias);
        return entry == null ? null : entry.getPrivateKey();
    }

119
    @Override
D
duke 已提交
120 121
    public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
            Socket socket) {
X
xuelei 已提交
122 123
        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
                        getAlgorithmConstraints(socket));
D
duke 已提交
124 125
    }

126
    @Override
D
duke 已提交
127 128
    public String chooseEngineClientAlias(String[] keyTypes,
            Principal[] issuers, SSLEngine engine) {
X
xuelei 已提交
129 130
        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
                        getAlgorithmConstraints(engine));
D
duke 已提交
131 132
    }

133
    @Override
D
duke 已提交
134 135
    public String chooseServerAlias(String keyType,
            Principal[] issuers, Socket socket) {
X
xuelei 已提交
136
        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
137 138 139 140 141 142 143 144 145 146 147 148
            getAlgorithmConstraints(socket),
            X509TrustManagerImpl.getRequestedServerNames(socket),
            "HTTPS");    // The SNI HostName is a fully qualified domain name.
                         // The certificate selection scheme for SNI HostName
                         // is similar to HTTPS endpoint identification scheme
                         // implemented in this provider.
                         //
                         // Using HTTPS endpoint identification scheme to guide
                         // the selection of an appropriate authentication
                         // certificate according to requested SNI extension.
                         //
                         // It is not a really HTTPS endpoint identification.
D
duke 已提交
149 150
    }

151
    @Override
D
duke 已提交
152 153
    public String chooseEngineServerAlias(String keyType,
            Principal[] issuers, SSLEngine engine) {
X
xuelei 已提交
154
        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
155 156 157 158 159 160 161 162 163 164 165 166
            getAlgorithmConstraints(engine),
            X509TrustManagerImpl.getRequestedServerNames(engine),
            "HTTPS");    // The SNI HostName is a fully qualified domain name.
                         // The certificate selection scheme for SNI HostName
                         // is similar to HTTPS endpoint identification scheme
                         // implemented in this provider.
                         //
                         // Using HTTPS endpoint identification scheme to guide
                         // the selection of an appropriate authentication
                         // certificate according to requested SNI extension.
                         //
                         // It is not a really HTTPS endpoint identification.
D
duke 已提交
167 168
    }

169
    @Override
D
duke 已提交
170
    public String[] getClientAliases(String keyType, Principal[] issuers) {
X
xuelei 已提交
171
        return getAliases(keyType, issuers, CheckType.CLIENT, null);
D
duke 已提交
172 173
    }

174
    @Override
D
duke 已提交
175
    public String[] getServerAliases(String keyType, Principal[] issuers) {
X
xuelei 已提交
176
        return getAliases(keyType, issuers, CheckType.SERVER, null);
D
duke 已提交
177 178 179 180 181 182
    }

    //
    // implementation private methods
    //

X
xuelei 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    // Gets algorithm constraints of the socket.
    private AlgorithmConstraints getAlgorithmConstraints(Socket socket) {
        if (socket != null && socket.isConnected() &&
                                        socket instanceof SSLSocket) {

            SSLSocket sslSocket = (SSLSocket)socket;
            SSLSession session = sslSocket.getHandshakeSession();

            if (session != null) {
                ProtocolVersion protocolVersion =
                    ProtocolVersion.valueOf(session.getProtocol());
                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                    String[] peerSupportedSignAlgs = null;

                    if (session instanceof ExtendedSSLSession) {
                        ExtendedSSLSession extSession =
                            (ExtendedSSLSession)session;
                        peerSupportedSignAlgs =
                            extSession.getPeerSupportedSignatureAlgorithms();
                    }

                    return new SSLAlgorithmConstraints(
                        sslSocket, peerSupportedSignAlgs, true);
                }
            }

            return new SSLAlgorithmConstraints(sslSocket, true);
        }

        return new SSLAlgorithmConstraints((SSLSocket)null, true);
    }

    // Gets algorithm constraints of the engine.
    private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) {
        if (engine != null) {
            SSLSession session = engine.getHandshakeSession();
            if (session != null) {
                ProtocolVersion protocolVersion =
                    ProtocolVersion.valueOf(session.getProtocol());
                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
                    String[] peerSupportedSignAlgs = null;

                    if (session instanceof ExtendedSSLSession) {
                        ExtendedSSLSession extSession =
                            (ExtendedSSLSession)session;
                        peerSupportedSignAlgs =
                            extSession.getPeerSupportedSignatureAlgorithms();
                    }

                    return new SSLAlgorithmConstraints(
                        engine, peerSupportedSignAlgs, true);
                }
            }
        }

        return new SSLAlgorithmConstraints(engine, true);
    }

D
duke 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    // we construct the alias we return to JSSE as seen in the code below
    // a unique id is included to allow us to reliably cache entries
    // between the calls to getCertificateChain() and getPrivateKey()
    // even if tokens are inserted or removed
    private String makeAlias(EntryStatus entry) {
        return uidCounter.incrementAndGet() + "." + entry.builderIndex + "."
                + entry.alias;
    }

    private PrivateKeyEntry getEntry(String alias) {
        // if the alias is null, return immediately
        if (alias == null) {
            return null;
        }

        // try to get the entry from cache
        Reference<PrivateKeyEntry> ref = entryCacheMap.get(alias);
        PrivateKeyEntry entry = (ref != null) ? ref.get() : null;
        if (entry != null) {
            return entry;
        }

        // parse the alias
        int firstDot = alias.indexOf('.');
        int secondDot = alias.indexOf('.', firstDot + 1);
        if ((firstDot == -1) || (secondDot == firstDot)) {
            // invalid alias
            return null;
        }
        try {
            int builderIndex = Integer.parseInt
                                (alias.substring(firstDot + 1, secondDot));
            String keyStoreAlias = alias.substring(secondDot + 1);
            Builder builder = builders.get(builderIndex);
            KeyStore ks = builder.getKeyStore();
            Entry newEntry = ks.getEntry
                    (keyStoreAlias, builder.getProtectionParameter(alias));
            if (newEntry instanceof PrivateKeyEntry == false) {
                // unexpected type of entry
                return null;
            }
            entry = (PrivateKeyEntry)newEntry;
283
            entryCacheMap.put(alias, new SoftReference<PrivateKeyEntry>(entry));
D
duke 已提交
284 285 286 287 288 289 290 291 292 293 294 295
            return entry;
        } catch (Exception e) {
            // ignore
            return null;
        }
    }

    // Class to help verify that the public key algorithm (and optionally
    // the signature algorithm) of a certificate matches what we need.
    private static class KeyType {

        final String keyAlgorithm;
X
xuelei 已提交
296 297 298 299 300 301 302

        // In TLS 1.2, the signature algorithm  has been obsoleted by the
        // supported_signature_algorithms, and the certificate type no longer
        // restricts the algorithm used to sign the certificate.
        // However, because we don't support certificate type checking other
        // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the
        // protocol version here.
D
duke 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
        final String sigKeyAlgorithm;

        KeyType(String algorithm) {
            int k = algorithm.indexOf("_");
            if (k == -1) {
                keyAlgorithm = algorithm;
                sigKeyAlgorithm = null;
            } else {
                keyAlgorithm = algorithm.substring(0, k);
                sigKeyAlgorithm = algorithm.substring(k + 1);
            }
        }

        boolean matches(Certificate[] chain) {
            if (!chain[0].getPublicKey().getAlgorithm().equals(keyAlgorithm)) {
                return false;
            }
            if (sigKeyAlgorithm == null) {
                return true;
            }
            if (chain.length > 1) {
                // if possible, check the public key in the issuer cert
X
xuelei 已提交
325 326
                return sigKeyAlgorithm.equals(
                        chain[1].getPublicKey().getAlgorithm());
D
duke 已提交
327 328 329 330 331 332 333 334 335 336 337 338
            } else {
                // Check the signature algorithm of the certificate itself.
                // Look for the "withRSA" in "SHA1withRSA", etc.
                X509Certificate issuer = (X509Certificate)chain[0];
                String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH);
                String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH);
                return sigAlgName.contains(pattern);
            }
        }
    }

    private static List<KeyType> getKeyTypes(String ... keyTypes) {
X
xuelei 已提交
339 340
        if ((keyTypes == null) ||
                (keyTypes.length == 0) || (keyTypes[0] == null)) {
D
duke 已提交
341 342
            return null;
        }
S
smarks 已提交
343
        List<KeyType> list = new ArrayList<>(keyTypes.length);
D
duke 已提交
344 345 346 347 348 349 350 351 352 353 354
        for (String keyType : keyTypes) {
            list.add(new KeyType(keyType));
        }
        return list;
    }

    /*
     * Return the best alias that fits the given parameters.
     * The algorithm we use is:
     *   . scan through all the aliases in all builders in order
     *   . as soon as we find a perfect match, return
355 356
     *     (i.e. a match with a cert that has appropriate key usage,
     *      qualified endpoint identity, and is not expired).
D
duke 已提交
357 358 359 360 361 362
     *   . if we do not find a perfect match, keep looping and remember
     *     the imperfect matches
     *   . at the end, sort the imperfect matches. we prefer expired certs
     *     with appropriate key usage to certs with the wrong key usage.
     *     return the first one of them.
     */
X
xuelei 已提交
363 364
    private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,
            CheckType checkType, AlgorithmConstraints constraints) {
365 366 367 368 369 370 371 372 373

        return chooseAlias(keyTypeList, issuers,
                                    checkType, constraints, null, null);
    }

    private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,
            CheckType checkType, AlgorithmConstraints constraints,
            List<SNIServerName> requestedServerNames, String idAlgorithm) {

374
        if (keyTypeList == null || keyTypeList.isEmpty()) {
D
duke 已提交
375 376 377 378 379 380 381
            return null;
        }

        Set<Principal> issuerSet = getIssuerSet(issuers);
        List<EntryStatus> allResults = null;
        for (int i = 0, n = builders.size(); i < n; i++) {
            try {
X
xuelei 已提交
382
                List<EntryStatus> results = getAliases(i, keyTypeList,
383 384
                            issuerSet, false, checkType, constraints,
                            requestedServerNames, idAlgorithm);
D
duke 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
                if (results != null) {
                    // the results will either be a single perfect match
                    // or 1 or more imperfect matches
                    // if it's a perfect match, return immediately
                    EntryStatus status = results.get(0);
                    if (status.checkResult == CheckResult.OK) {
                        if (useDebug) {
                            debug.println("KeyMgr: choosing key: " + status);
                        }
                        return makeAlias(status);
                    }
                    if (allResults == null) {
                        allResults = new ArrayList<EntryStatus>();
                    }
                    allResults.addAll(results);
                }
            } catch (Exception e) {
                // ignore
            }
        }
        if (allResults == null) {
            if (useDebug) {
                debug.println("KeyMgr: no matching key found");
            }
            return null;
        }
        Collections.sort(allResults);
        if (useDebug) {
            debug.println("KeyMgr: no good matching key found, "
                        + "returning best match out of:");
            debug.println(allResults.toString());
        }
        return makeAlias(allResults.get(0));
    }

    /*
     * Return all aliases that (approximately) fit the parameters.
     * These are perfect matches plus imperfect matches (expired certificates
     * and certificates with the wrong extensions).
     * The perfect matches will be first in the array.
     */
    public String[] getAliases(String keyType, Principal[] issuers,
X
xuelei 已提交
427
            CheckType checkType, AlgorithmConstraints constraints) {
D
duke 已提交
428 429 430 431 432 433 434 435 436
        if (keyType == null) {
            return null;
        }

        Set<Principal> issuerSet = getIssuerSet(issuers);
        List<KeyType> keyTypeList = getKeyTypes(keyType);
        List<EntryStatus> allResults = null;
        for (int i = 0, n = builders.size(); i < n; i++) {
            try {
X
xuelei 已提交
437
                List<EntryStatus> results = getAliases(i, keyTypeList,
438 439
                                    issuerSet, true, checkType, constraints,
                                    null, null);
D
duke 已提交
440 441 442 443 444 445 446 447 448 449
                if (results != null) {
                    if (allResults == null) {
                        allResults = new ArrayList<EntryStatus>();
                    }
                    allResults.addAll(results);
                }
            } catch (Exception e) {
                // ignore
            }
        }
450
        if (allResults == null || allResults.isEmpty()) {
D
duke 已提交
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
            if (useDebug) {
                debug.println("KeyMgr: no matching alias found");
            }
            return null;
        }
        Collections.sort(allResults);
        if (useDebug) {
            debug.println("KeyMgr: getting aliases: " + allResults);
        }
        return toAliases(allResults);
    }

    // turn candidate entries into unique aliases we can return to JSSE
    private String[] toAliases(List<EntryStatus> results) {
        String[] s = new String[results.size()];
        int i = 0;
        for (EntryStatus result : results) {
            s[i++] = makeAlias(result);
        }
        return s;
    }

    // make a Set out of the array
    private Set<Principal> getIssuerSet(Principal[] issuers) {
        if ((issuers != null) && (issuers.length != 0)) {
S
smarks 已提交
476
            return new HashSet<>(Arrays.asList(issuers));
D
duke 已提交
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
        } else {
            return null;
        }
    }

    // a candidate match
    // identifies the entry by builder and alias
    // and includes the result of the certificate check
    private static class EntryStatus implements Comparable<EntryStatus> {

        final int builderIndex;
        final int keyIndex;
        final String alias;
        final CheckResult checkResult;

        EntryStatus(int builderIndex, int keyIndex, String alias,
                Certificate[] chain, CheckResult checkResult) {
            this.builderIndex = builderIndex;
            this.keyIndex = keyIndex;
            this.alias = alias;
            this.checkResult = checkResult;
        }

500
        @Override
D
duke 已提交
501 502 503 504 505
        public int compareTo(EntryStatus other) {
            int result = this.checkResult.compareTo(other.checkResult);
            return (result == 0) ? (this.keyIndex - other.keyIndex) : result;
        }

506
        @Override
D
duke 已提交
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
        public String toString() {
            String s = alias + " (verified: " + checkResult + ")";
            if (builderIndex == 0) {
                return s;
            } else {
                return "Builder #" + builderIndex + ", alias: " + s;
            }
        }
    }

    // enum for the type of certificate check we want to perform
    // (client or server)
    // also includes the check code itself
    private static enum CheckType {

        // enum constant for "no check" (currently not used)
        NONE(Collections.<String>emptySet()),

        // enum constant for "tls client" check
        // valid EKU for TLS client: any, tls_client
        CLIENT(new HashSet<String>(Arrays.asList(new String[] {
            "2.5.29.37.0", "1.3.6.1.5.5.7.3.2" }))),

        // enum constant for "tls server" check
        // valid EKU for TLS server: any, tls_server, ns_sgc, ms_sgc
        SERVER(new HashSet<String>(Arrays.asList(new String[] {
            "2.5.29.37.0", "1.3.6.1.5.5.7.3.1", "2.16.840.1.113730.4.1",
            "1.3.6.1.4.1.311.10.3.3" })));

        // set of valid EKU values for this type
        final Set<String> validEku;

        CheckType(Set<String> validEku) {
            this.validEku = validEku;
        }

        private static boolean getBit(boolean[] keyUsage, int bit) {
            return (bit < keyUsage.length) && keyUsage[bit];
        }

        // check if this certificate is appropriate for this type of use
        // first check extensions, if they match, check expiration
        // note: we may want to move this code into the sun.security.validator
        // package
551 552 553
        CheckResult check(X509Certificate cert, Date date,
                List<SNIServerName> serverNames, String idAlgorithm) {

D
duke 已提交
554 555 556 557 558 559 560 561
            if (this == NONE) {
                return CheckResult.OK;
            }

            // check extensions
            try {
                // check extended key usage
                List<String> certEku = cert.getExtendedKeyUsage();
X
xuelei 已提交
562 563
                if ((certEku != null) &&
                        Collections.disjoint(validEku, certEku)) {
D
duke 已提交
564 565 566 567 568 569 570 571 572 573
                    // if extension present and it does not contain any of
                    // the valid EKU OIDs, return extension_mismatch
                    return CheckResult.EXTENSION_MISMATCH;
                }

                // check key usage
                boolean[] ku = cert.getKeyUsage();
                if (ku != null) {
                    String algorithm = cert.getPublicKey().getAlgorithm();
                    boolean kuSignature = getBit(ku, 0);
574 575 576 577 578 579 580 581 582 583 584 585 586
                    switch (algorithm) {
                        case "RSA":
                            // require either signature bit
                            // or if server also allow key encipherment bit
                            if (kuSignature == false) {
                                if ((this == CLIENT) || (getBit(ku, 2) == false)) {
                                    return CheckResult.EXTENSION_MISMATCH;
                                }
                            }
                            break;
                        case "DSA":
                            // require signature bit
                            if (kuSignature == false) {
D
duke 已提交
587 588
                                return CheckResult.EXTENSION_MISMATCH;
                            }
589 590 591 592 593 594 595 596 597 598 599 600 601
                            break;
                        case "DH":
                            // require keyagreement bit
                            if (getBit(ku, 4) == false) {
                                return CheckResult.EXTENSION_MISMATCH;
                            }
                            break;
                        case "EC":
                            // require signature bit
                            if (kuSignature == false) {
                                return CheckResult.EXTENSION_MISMATCH;
                            }
                            // For servers, also require key agreement.
602 603 604 605 606
                            // This is not totally accurate as the keyAgreement
                            // bit is only necessary for static ECDH key
                            // exchange and not ephemeral ECDH. We leave it in
                            // for now until there are signs that this check
                            // causes problems for real world EC certificates.
607 608 609 610
                            if ((this == SERVER) && (getBit(ku, 4) == false)) {
                                return CheckResult.EXTENSION_MISMATCH;
                            }
                            break;
D
duke 已提交
611 612 613 614 615 616 617 618 619 620 621 622
                    }
                }
            } catch (CertificateException e) {
                // extensions unparseable, return failure
                return CheckResult.EXTENSION_MISMATCH;
            }

            try {
                cert.checkValidity(date);
            } catch (CertificateException e) {
                return CheckResult.EXPIRED;
            }
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

            if (serverNames != null && !serverNames.isEmpty()) {
                for (SNIServerName serverName : serverNames) {
                    if (serverName.getType() ==
                                StandardConstants.SNI_HOST_NAME) {
                        if (!(serverName instanceof SNIHostName)) {
                            try {
                                serverName =
                                    new SNIHostName(serverName.getEncoded());
                            } catch (IllegalArgumentException iae) {
                                // unlikely to happen, just in case ...
                                if (useDebug) {
                                    debug.println(
                                       "Illegal server name: " + serverName);
                                }

                                return CheckResult.INSENSITIVE;
                            }
                        }
                        String hostname =
                                ((SNIHostName)serverName).getAsciiName();

                        try {
                            X509TrustManagerImpl.checkIdentity(hostname,
                                                        cert, idAlgorithm);
                        } catch (CertificateException e) {
                            if (useDebug) {
                                debug.println(
                                   "Certificate identity does not match " +
                                   "Server Name Inidication (SNI): " +
                                   hostname);
                            }
                            return CheckResult.INSENSITIVE;
                        }

                        break;
                    }
                }
            }

            return CheckResult.OK;
D
duke 已提交
664
        }
665 666 667 668 669 670 671 672 673

        public String getValidator() {
            if (this == CLIENT) {
                return Validator.VAR_TLS_CLIENT;
            } else if (this == SERVER) {
                return Validator.VAR_TLS_SERVER;
            }
            return Validator.VAR_GENERIC;
        }
D
duke 已提交
674 675 676 677 678 679 680
    }

    // enum for the result of the extension check
    // NOTE: the order of the constants is important as they are used
    // for sorting, i.e. OK is best, followed by EXPIRED and EXTENSION_MISMATCH
    private static enum CheckResult {
        OK,                     // ok or not checked
681
        INSENSITIVE,            // server name indication insensitive
D
duke 已提交
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
        EXPIRED,                // extensions valid but cert expired
        EXTENSION_MISMATCH,     // extensions invalid (expiration not checked)
    }

    /*
     * Return a List of all candidate matches in the specified builder
     * that fit the parameters.
     * We exclude entries in the KeyStore if they are not:
     *  . private key entries
     *  . the certificates are not X509 certificates
     *  . the algorithm of the key in the EE cert doesn't match one of keyTypes
     *  . none of the certs is issued by a Principal in issuerSet
     * Using those entries would not be possible or they would almost
     * certainly be rejected by the peer.
     *
     * In addition to those checks, we also check the extensions in the EE
     * cert and its expiration. Even if there is a mismatch, we include
     * such certificates because they technically work and might be accepted
     * by the peer. This leads to more graceful failure and better error
     * messages if the cert expires from one day to the next.
     *
     * The return values are:
     *   . null, if there are no matching entries at all
     *   . if 'findAll' is 'false' and there is a perfect match, a List
     *     with a single element (early return)
     *   . if 'findAll' is 'false' and there is NO perfect match, a List
     *     with all the imperfect matches (expired, wrong extensions)
     *   . if 'findAll' is 'true', a List with all perfect and imperfect
     *     matches
     */
    private List<EntryStatus> getAliases(int builderIndex,
            List<KeyType> keyTypes, Set<Principal> issuerSet,
X
xuelei 已提交
714
            boolean findAll, CheckType checkType,
715 716 717 718
            AlgorithmConstraints constraints,
            List<SNIServerName> requestedServerNames,
            String idAlgorithm) throws Exception {

D
duke 已提交
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
        Builder builder = builders.get(builderIndex);
        KeyStore ks = builder.getKeyStore();
        List<EntryStatus> results = null;
        Date date = verificationDate;
        boolean preferred = false;
        for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
            String alias = e.nextElement();
            // check if it is a key entry (private key or secret key)
            if (ks.isKeyEntry(alias) == false) {
                continue;
            }

            Certificate[] chain = ks.getCertificateChain(alias);
            if ((chain == null) || (chain.length == 0)) {
                // must be secret key entry, ignore
                continue;
            }
X
xuelei 已提交
736 737 738 739 740 741 742 743 744 745 746 747 748

            boolean incompatible = false;
            for (Certificate cert : chain) {
                if (cert instanceof X509Certificate == false) {
                    // not an X509Certificate, ignore this alias
                    incompatible = true;
                    break;
                }
            }
            if (incompatible) {
                continue;
            }

D
duke 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
            // check keytype
            int keyIndex = -1;
            int j = 0;
            for (KeyType keyType : keyTypes) {
                if (keyType.matches(chain)) {
                    keyIndex = j;
                    break;
                }
                j++;
            }
            if (keyIndex == -1) {
                if (useDebug) {
                    debug.println("Ignoring alias " + alias
                                + ": key algorithm does not match");
                }
                continue;
            }
            // check issuers
            if (issuerSet != null) {
                boolean found = false;
                for (Certificate cert : chain) {
                    X509Certificate xcert = (X509Certificate)cert;
                    if (issuerSet.contains(xcert.getIssuerX500Principal())) {
                        found = true;
                        break;
                    }
                }
                if (found == false) {
                    if (useDebug) {
                        debug.println("Ignoring alias " + alias
                                    + ": issuers do not match");
                    }
                    continue;
                }
            }
X
xuelei 已提交
784 785 786

            // check the algorithm constraints
            if (constraints != null &&
787 788
                    !conformsToAlgorithmConstraints(constraints, chain,
                            checkType.getValidator())) {
X
xuelei 已提交
789 790 791 792 793 794 795 796 797

                if (useDebug) {
                    debug.println("Ignoring alias " + alias +
                            ": certificate list does not conform to " +
                            "algorithm constraints");
                }
                continue;
            }

D
duke 已提交
798 799 800 801
            if (date == null) {
                date = new Date();
            }
            CheckResult checkResult =
802 803
                    checkType.check((X509Certificate)chain[0], date,
                                    requestedServerNames, idAlgorithm);
D
duke 已提交
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
            EntryStatus status =
                    new EntryStatus(builderIndex, keyIndex,
                                        alias, chain, checkResult);
            if (!preferred && checkResult == CheckResult.OK && keyIndex == 0) {
                preferred = true;
            }
            if (preferred && (findAll == false)) {
                // if we have a good match and do not need all matches,
                // return immediately
                return Collections.singletonList(status);
            } else {
                if (results == null) {
                    results = new ArrayList<EntryStatus>();
                }
                results.add(status);
            }
        }
        return results;
    }

X
xuelei 已提交
824
    private static boolean conformsToAlgorithmConstraints(
825 826
            AlgorithmConstraints constraints, Certificate[] chain,
            String variant) {
X
xuelei 已提交
827

828
        AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant);
X
xuelei 已提交
829 830 831 832
        try {
            checker.init(false);
        } catch (CertPathValidatorException cpve) {
            // unlikely to happen
833 834 835 836 837
            if (useDebug) {
                debug.println(
                    "Cannot initialize algorithm constraints checker: " + cpve);
            }

X
xuelei 已提交
838 839 840 841 842 843 844 845 846 847
            return false;
        }

        // It is a forward checker, so we need to check from trust to target.
        for (int i = chain.length - 1; i >= 0; i--) {
            Certificate cert = chain[i];
            try {
                // We don't care about the unresolved critical extensions.
                checker.check(cert, Collections.<String>emptySet());
            } catch (CertPathValidatorException cpve) {
848 849 850 851 852
                if (useDebug) {
                    debug.println("Certificate (" + cert +
                        ") does not conform to algorithm constraints: " + cpve);
                }

X
xuelei 已提交
853 854 855 856 857 858 859
                return false;
            }
        }

        return true;
    }

D
duke 已提交
860
}