jdk/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java
author xuelei
Thu, 13 Nov 2008 23:25:10 -0800
changeset 1580 9af5946d4060
parent 2 90ce3da70b43
child 5506 202f599c92aa
permissions -rw-r--r--
6745052: SLServerSocket file descriptor leak Summary: SSLServerSocketImpl.checkEnabledSuites() does not release the temporary socket properly Reviewed-by: wetmore, weijun
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 2004-2007 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package sun.security.ssl;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.lang.ref.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.util.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import static java.util.Locale.ENGLISH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.util.concurrent.atomic.AtomicLong;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.net.Socket;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
import java.security.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.security.KeyStore.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
import java.security.cert.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.security.cert.Certificate;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import javax.net.ssl.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 * The new X509 key manager implementation. The main differences to the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * old SunX509 key manager are:
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 *  . it is based around the KeyStore.Builder API. This allows it to use
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 *    other forms of KeyStore protection or password input (e.g. a
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 *    CallbackHandler) or to have keys within one KeyStore protected by
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 *    different keys.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 *  . it can use multiple KeyStores at the same time.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 *  . it is explicitly designed to accomodate KeyStores that change over
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 *    the lifetime of the process.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 *  . it makes an effort to choose the key that matches best, i.e. one that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 *    is not expired and has the appropriate certificate extensions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 * Note that this code is not explicitly performance optimzied yet.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
 * @author  Andreas Sterbenz
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
final class X509KeyManagerImpl extends X509ExtendedKeyManager
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
        implements X509KeyManager {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    private static final Debug debug = Debug.getInstance("ssl");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    private final static boolean useDebug =
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
                            (debug != null) && Debug.isOn("keymanager");
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    // for unit testing only, set via privileged reflection
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
    private static Date verificationDate;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
    // list of the builders
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
    private final List<Builder> builders;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
    // counter to generate unique ids for the aliases
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    private final AtomicLong uidCounter;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
    // cached entries
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
    private final Map<String,Reference<PrivateKeyEntry>> entryCacheMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
    X509KeyManagerImpl(Builder builder) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
        this(Collections.singletonList(builder));
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
    X509KeyManagerImpl(List<Builder> builders) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
        this.builders = builders;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
        uidCounter = new AtomicLong();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
        entryCacheMap = Collections.synchronizedMap
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
                        (new SizedMap<String,Reference<PrivateKeyEntry>>());
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
    // LinkedHashMap with a max size of 10
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
    // see LinkedHashMap JavaDocs
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
    private static class SizedMap<K,V> extends LinkedHashMap<K,V> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
        @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
            return size() > 10;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
    // public methods
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
    public X509Certificate[] getCertificateChain(String alias) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
        PrivateKeyEntry entry = getEntry(alias);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
        return entry == null ? null :
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
                (X509Certificate[])entry.getCertificateChain();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
    public PrivateKey getPrivateKey(String alias) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
        PrivateKeyEntry entry = getEntry(alias);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
        return entry == null ? null : entry.getPrivateKey();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
    public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
            Socket socket) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
    public String chooseEngineClientAlias(String[] keyTypes,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
            Principal[] issuers, SSLEngine engine) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
        return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
    public String chooseServerAlias(String keyType,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
            Principal[] issuers, Socket socket) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
    public String chooseEngineServerAlias(String keyType,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
            Principal[] issuers, SSLEngine engine) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
    public String[] getClientAliases(String keyType, Principal[] issuers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
        return getAliases(keyType, issuers, CheckType.CLIENT);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
    public String[] getServerAliases(String keyType, Principal[] issuers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
        return getAliases(keyType, issuers, CheckType.SERVER);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
    // implementation private methods
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
    // we construct the alias we return to JSSE as seen in the code below
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
    // a unique id is included to allow us to reliably cache entries
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
    // between the calls to getCertificateChain() and getPrivateKey()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
    // even if tokens are inserted or removed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
    private String makeAlias(EntryStatus entry) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
        return uidCounter.incrementAndGet() + "." + entry.builderIndex + "."
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
                + entry.alias;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
    private PrivateKeyEntry getEntry(String alias) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
        // if the alias is null, return immediately
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
        if (alias == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
        // try to get the entry from cache
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
        Reference<PrivateKeyEntry> ref = entryCacheMap.get(alias);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        PrivateKeyEntry entry = (ref != null) ? ref.get() : null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        if (entry != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
            return entry;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
        // parse the alias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
        int firstDot = alias.indexOf('.');
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
        int secondDot = alias.indexOf('.', firstDot + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
        if ((firstDot == -1) || (secondDot == firstDot)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
            // invalid alias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
            int builderIndex = Integer.parseInt
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
                                (alias.substring(firstDot + 1, secondDot));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
            String keyStoreAlias = alias.substring(secondDot + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
            Builder builder = builders.get(builderIndex);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
            KeyStore ks = builder.getKeyStore();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
            Entry newEntry = ks.getEntry
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
                    (keyStoreAlias, builder.getProtectionParameter(alias));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
            if (newEntry instanceof PrivateKeyEntry == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
                // unexpected type of entry
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
            entry = (PrivateKeyEntry)newEntry;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
            entryCacheMap.put(alias, new SoftReference(entry));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
            return entry;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
        } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
            // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
    // Class to help verify that the public key algorithm (and optionally
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
    // the signature algorithm) of a certificate matches what we need.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
    private static class KeyType {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
        final String keyAlgorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
        final String sigKeyAlgorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
        KeyType(String algorithm) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
            int k = algorithm.indexOf("_");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
            if (k == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
                keyAlgorithm = algorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
                sigKeyAlgorithm = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
                keyAlgorithm = algorithm.substring(0, k);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
                sigKeyAlgorithm = algorithm.substring(k + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
        boolean matches(Certificate[] chain) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
            if (!chain[0].getPublicKey().getAlgorithm().equals(keyAlgorithm)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
            if (sigKeyAlgorithm == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
            if (chain.length > 1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
                // if possible, check the public key in the issuer cert
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
                return sigKeyAlgorithm.equals(chain[1].getPublicKey().getAlgorithm());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
                // Check the signature algorithm of the certificate itself.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
                // Look for the "withRSA" in "SHA1withRSA", etc.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
                X509Certificate issuer = (X509Certificate)chain[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
                String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
                String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
                return sigAlgName.contains(pattern);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
    private static List<KeyType> getKeyTypes(String ... keyTypes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
        if ((keyTypes == null) || (keyTypes.length == 0) || (keyTypes[0] == null)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
        List<KeyType> list = new ArrayList<KeyType>(keyTypes.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
        for (String keyType : keyTypes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
            list.add(new KeyType(keyType));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
        return list;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
     * Return the best alias that fits the given parameters.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
     * The algorithm we use is:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
     *   . scan through all the aliases in all builders in order
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
     *   . as soon as we find a perfect match, return
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
     *     (i.e. a match with a cert that has appropriate key usage
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
     *      and is not expired).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
     *   . if we do not find a perfect match, keep looping and remember
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
     *     the imperfect matches
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
     *   . at the end, sort the imperfect matches. we prefer expired certs
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
     *     with appropriate key usage to certs with the wrong key usage.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
     *     return the first one of them.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
    private String chooseAlias(List<KeyType> keyTypeList,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
            Principal[] issuers, CheckType checkType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
        if (keyTypeList == null || keyTypeList.size() == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
        Set<Principal> issuerSet = getIssuerSet(issuers);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
        List<EntryStatus> allResults = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
        for (int i = 0, n = builders.size(); i < n; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
                List<EntryStatus> results =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
                    getAliases(i, keyTypeList, issuerSet, false, checkType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
                if (results != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
                    // the results will either be a single perfect match
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
                    // or 1 or more imperfect matches
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
                    // if it's a perfect match, return immediately
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
                    EntryStatus status = results.get(0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
                    if (status.checkResult == CheckResult.OK) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
                        if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
                            debug.println("KeyMgr: choosing key: " + status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
                        return makeAlias(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
                    if (allResults == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
                        allResults = new ArrayList<EntryStatus>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
                    allResults.addAll(results);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
        if (allResults == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
            if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
                debug.println("KeyMgr: no matching key found");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
        Collections.sort(allResults);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
        if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
            debug.println("KeyMgr: no good matching key found, "
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
                        + "returning best match out of:");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
            debug.println(allResults.toString());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
        return makeAlias(allResults.get(0));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
     * Return all aliases that (approximately) fit the parameters.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
     * These are perfect matches plus imperfect matches (expired certificates
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
     * and certificates with the wrong extensions).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
     * The perfect matches will be first in the array.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
    public String[] getAliases(String keyType, Principal[] issuers,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
            CheckType checkType) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
        if (keyType == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
        Set<Principal> issuerSet = getIssuerSet(issuers);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
        List<KeyType> keyTypeList = getKeyTypes(keyType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
        List<EntryStatus> allResults = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
        for (int i = 0, n = builders.size(); i < n; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
                List<EntryStatus> results =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
                        getAliases(i, keyTypeList, issuerSet, true, checkType);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
                if (results != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
                    if (allResults == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
                        allResults = new ArrayList<EntryStatus>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
                    allResults.addAll(results);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
                // ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
        if (allResults == null || allResults.size() == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
            if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
                debug.println("KeyMgr: no matching alias found");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
        Collections.sort(allResults);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
        if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
            debug.println("KeyMgr: getting aliases: " + allResults);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
        return toAliases(allResults);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
    // turn candidate entries into unique aliases we can return to JSSE
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
    private String[] toAliases(List<EntryStatus> results) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
        String[] s = new String[results.size()];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
        int i = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
        for (EntryStatus result : results) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
            s[i++] = makeAlias(result);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
        return s;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
    // make a Set out of the array
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
    private Set<Principal> getIssuerSet(Principal[] issuers) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
        if ((issuers != null) && (issuers.length != 0)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
            return new HashSet<Principal>(Arrays.asList(issuers));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
            return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
    // a candidate match
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
    // identifies the entry by builder and alias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
    // and includes the result of the certificate check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
    private static class EntryStatus implements Comparable<EntryStatus> {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
        final int builderIndex;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
        final int keyIndex;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
        final String alias;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
        final CheckResult checkResult;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
        EntryStatus(int builderIndex, int keyIndex, String alias,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
                Certificate[] chain, CheckResult checkResult) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
            this.builderIndex = builderIndex;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
            this.keyIndex = keyIndex;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
            this.alias = alias;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
            this.checkResult = checkResult;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
        public int compareTo(EntryStatus other) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
            int result = this.checkResult.compareTo(other.checkResult);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
            return (result == 0) ? (this.keyIndex - other.keyIndex) : result;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
        public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
            String s = alias + " (verified: " + checkResult + ")";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
            if (builderIndex == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
                return s;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
                return "Builder #" + builderIndex + ", alias: " + s;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
    // enum for the type of certificate check we want to perform
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
    // (client or server)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
    // also includes the check code itself
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
    private static enum CheckType {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
        // enum constant for "no check" (currently not used)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
        NONE(Collections.<String>emptySet()),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
        // enum constant for "tls client" check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
        // valid EKU for TLS client: any, tls_client
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
        CLIENT(new HashSet<String>(Arrays.asList(new String[] {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
            "2.5.29.37.0", "1.3.6.1.5.5.7.3.2" }))),
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
        // enum constant for "tls server" check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
        // valid EKU for TLS server: any, tls_server, ns_sgc, ms_sgc
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
        SERVER(new HashSet<String>(Arrays.asList(new String[] {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
            "2.5.29.37.0", "1.3.6.1.5.5.7.3.1", "2.16.840.1.113730.4.1",
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
            "1.3.6.1.4.1.311.10.3.3" })));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
        // set of valid EKU values for this type
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
        final Set<String> validEku;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
        CheckType(Set<String> validEku) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
            this.validEku = validEku;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
        private static boolean getBit(boolean[] keyUsage, int bit) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
            return (bit < keyUsage.length) && keyUsage[bit];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
        // check if this certificate is appropriate for this type of use
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
        // first check extensions, if they match, check expiration
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
        // note: we may want to move this code into the sun.security.validator
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
        // package
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
        CheckResult check(X509Certificate cert, Date date) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
            if (this == NONE) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
                return CheckResult.OK;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
            // check extensions
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
                // check extended key usage
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
                List<String> certEku = cert.getExtendedKeyUsage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
                if ((certEku != null) && Collections.disjoint(validEku, certEku)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
                    // if extension present and it does not contain any of
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
                    // the valid EKU OIDs, return extension_mismatch
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
                    return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
                // check key usage
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
                boolean[] ku = cert.getKeyUsage();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
                if (ku != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
                    String algorithm = cert.getPublicKey().getAlgorithm();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
                    boolean kuSignature = getBit(ku, 0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
                    if (algorithm.equals("RSA")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
                        // require either signature bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
                        // or if server also allow key encipherment bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
                        if (kuSignature == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
                            if ((this == CLIENT) || (getBit(ku, 2) == false)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
                                return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
                    } else if (algorithm.equals("DSA")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
                        // require signature bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
                        if (kuSignature == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
                            return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
                    } else if (algorithm.equals("DH")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
                        // require keyagreement bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
                        if (getBit(ku, 4) == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
                            return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
                    } else if (algorithm.equals("EC")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
                        // require signature bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
                        if (kuSignature == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
                            return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
                        // For servers, also require key agreement.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
                        // This is not totally accurate as the keyAgreement bit
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
                        // is only necessary for static ECDH key exchange and
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
                        // not ephemeral ECDH. We leave it in for now until
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
                        // there are signs that this check causes problems
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
                        // for real world EC certificates.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
                        if ((this == SERVER) && (getBit(ku, 4) == false)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
                            return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
            } catch (CertificateException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
                // extensions unparseable, return failure
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
                return CheckResult.EXTENSION_MISMATCH;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
                cert.checkValidity(date);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
                return CheckResult.OK;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
            } catch (CertificateException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
                return CheckResult.EXPIRED;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
    // enum for the result of the extension check
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
    // NOTE: the order of the constants is important as they are used
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
    // for sorting, i.e. OK is best, followed by EXPIRED and EXTENSION_MISMATCH
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
    private static enum CheckResult {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
        OK,                     // ok or not checked
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
        EXPIRED,                // extensions valid but cert expired
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
        EXTENSION_MISMATCH,     // extensions invalid (expiration not checked)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
     * Return a List of all candidate matches in the specified builder
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
     * that fit the parameters.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
     * We exclude entries in the KeyStore if they are not:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
     *  . private key entries
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
     *  . the certificates are not X509 certificates
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
     *  . the algorithm of the key in the EE cert doesn't match one of keyTypes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
     *  . none of the certs is issued by a Principal in issuerSet
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
     * Using those entries would not be possible or they would almost
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
     * certainly be rejected by the peer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
     * In addition to those checks, we also check the extensions in the EE
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
     * cert and its expiration. Even if there is a mismatch, we include
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
     * such certificates because they technically work and might be accepted
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
     * by the peer. This leads to more graceful failure and better error
90ce3da70b43 Initial load
duke
parents:
diff changeset
   524
     * messages if the cert expires from one day to the next.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
     * The return values are:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
     *   . null, if there are no matching entries at all
90ce3da70b43 Initial load
duke
parents:
diff changeset
   528
     *   . if 'findAll' is 'false' and there is a perfect match, a List
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
     *     with a single element (early return)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
     *   . if 'findAll' is 'false' and there is NO perfect match, a List
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
     *     with all the imperfect matches (expired, wrong extensions)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
     *   . if 'findAll' is 'true', a List with all perfect and imperfect
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
     *     matches
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   535
    private List<EntryStatus> getAliases(int builderIndex,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   536
            List<KeyType> keyTypes, Set<Principal> issuerSet,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   537
            boolean findAll, CheckType checkType) throws Exception {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   538
        Builder builder = builders.get(builderIndex);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   539
        KeyStore ks = builder.getKeyStore();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
        List<EntryStatus> results = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
        Date date = verificationDate;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
        boolean preferred = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
        for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
            String alias = e.nextElement();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   545
            // check if it is a key entry (private key or secret key)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
            if (ks.isKeyEntry(alias) == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
            Certificate[] chain = ks.getCertificateChain(alias);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
            if ((chain == null) || (chain.length == 0)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
                // must be secret key entry, ignore
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
            // check keytype
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
            int keyIndex = -1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
            int j = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
            for (KeyType keyType : keyTypes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
                if (keyType.matches(chain)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
                    keyIndex = j;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
                j++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   565
            if (keyIndex == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
                if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
                    debug.println("Ignoring alias " + alias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
                                + ": key algorithm does not match");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
            // check issuers
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
            if (issuerSet != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
                boolean found = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
                for (Certificate cert : chain) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
                    if (cert instanceof X509Certificate == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
                        // not an X509Certificate, ignore this entry
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
                    X509Certificate xcert = (X509Certificate)cert;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
                    if (issuerSet.contains(xcert.getIssuerX500Principal())) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
                        found = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
                        break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
                if (found == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
                    if (useDebug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
                        debug.println("Ignoring alias " + alias
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
                                    + ": issuers do not match");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
                    continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
            if (date == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
                date = new Date();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   596
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   597
            CheckResult checkResult =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   598
                    checkType.check((X509Certificate)chain[0], date);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   599
            EntryStatus status =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   600
                    new EntryStatus(builderIndex, keyIndex,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   601
                                        alias, chain, checkResult);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
            if (!preferred && checkResult == CheckResult.OK && keyIndex == 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
                preferred = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
            if (preferred && (findAll == false)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
                // if we have a good match and do not need all matches,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
                // return immediately
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
                return Collections.singletonList(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
            } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
                if (results == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
                    results = new ArrayList<EntryStatus>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
                results.add(status);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
        return results;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
}