1/*
2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.provider.certpath;
27
28import java.io.IOException;
29import java.security.cert.CertificateException;
30import java.security.cert.CertPathValidatorException;
31import java.security.cert.PKIXCertPathChecker;
32import java.security.cert.X509Certificate;
33import java.util.ArrayList;
34import java.util.HashSet;
35import java.util.List;
36import java.util.ListIterator;
37import javax.security.auth.x500.X500Principal;
38
39import sun.security.util.Debug;
40import sun.security.x509.SubjectAlternativeNameExtension;
41import sun.security.x509.GeneralNames;
42import sun.security.x509.GeneralName;
43import sun.security.x509.GeneralNameInterface;
44import sun.security.x509.X500Name;
45import sun.security.x509.X509CertImpl;
46
47/**
48 * A specification of a forward PKIX validation state
49 * which is initialized by each build and updated each time a
50 * certificate is added to the current path.
51 * @since       1.4
52 * @author      Yassir Elley
53 */
54class ForwardState implements State {
55
56    private static final Debug debug = Debug.getInstance("certpath");
57
58    /* The issuer DN of the last cert in the path */
59    X500Principal issuerDN;
60
61    /* The last cert in the path */
62    X509CertImpl cert;
63
64    /* The set of subjectDNs and subjectAltNames of all certs in the path */
65    HashSet<GeneralNameInterface> subjectNamesTraversed;
66
67    /*
68     * The number of intermediate CA certs which have been traversed so
69     * far in the path
70     */
71    int traversedCACerts;
72
73    /* Flag indicating if state is initial (path is just starting) */
74    private boolean init = true;
75
76
77    /* the untrusted certificates checker */
78    // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
79    // UntrustedChecker untrustedChecker;
80
81    /* The list of user-defined checkers that support forward checking */
82    ArrayList<PKIXCertPathChecker> forwardCheckers;
83
84    /* Flag indicating if key needing to inherit key parameters has been
85     * encountered.
86     */
87    boolean keyParamsNeededFlag = false;
88
89    /**
90     * Returns a boolean flag indicating if the state is initial
91     * (just starting)
92     *
93     * @return boolean flag indicating if the state is initial (just starting)
94     */
95    @Override
96    public boolean isInitial() {
97        return init;
98    }
99
100    /**
101     * Return boolean flag indicating whether a public key that needs to inherit
102     * key parameters has been encountered.
103     *
104     * @return boolean true if key needing to inherit parameters has been
105     * encountered; false otherwise.
106     */
107    @Override
108    public boolean keyParamsNeeded() {
109        return keyParamsNeededFlag;
110    }
111
112    /**
113     * Display state for debugging purposes
114     */
115    @Override
116    public String toString() {
117        StringBuilder sb = new StringBuilder();
118        sb.append("State [");
119        sb.append("\n  issuerDN of last cert: ").append(issuerDN);
120        sb.append("\n  traversedCACerts: ").append(traversedCACerts);
121        sb.append("\n  init: ").append(String.valueOf(init));
122        sb.append("\n  keyParamsNeeded: ").append
123                 (String.valueOf(keyParamsNeededFlag));
124        sb.append("\n  subjectNamesTraversed: \n").append
125                 (subjectNamesTraversed);
126        sb.append("]\n");
127        return sb.toString();
128    }
129
130    /**
131     * Initialize the state.
132     *
133     * @param certPathCheckers the list of user-defined PKIXCertPathCheckers
134     */
135    public void initState(List<PKIXCertPathChecker> certPathCheckers)
136        throws CertPathValidatorException
137    {
138        subjectNamesTraversed = new HashSet<GeneralNameInterface>();
139        traversedCACerts = 0;
140
141        /*
142         * Populate forwardCheckers with every user-defined checker
143         * that supports forward checking and initialize the forwardCheckers
144         */
145        forwardCheckers = new ArrayList<PKIXCertPathChecker>();
146        for (PKIXCertPathChecker checker : certPathCheckers) {
147            if (checker.isForwardCheckingSupported()) {
148                checker.init(true);
149                forwardCheckers.add(checker);
150            }
151        }
152
153        init = true;
154    }
155
156    /**
157     * Update the state with the next certificate added to the path.
158     *
159     * @param cert the certificate which is used to update the state
160     */
161    @Override
162    public void updateState(X509Certificate cert)
163        throws CertificateException, IOException, CertPathValidatorException {
164
165        if (cert == null)
166            return;
167
168        X509CertImpl icert = X509CertImpl.toImpl(cert);
169
170        /* see if certificate key has null parameters */
171        if (PKIX.isDSAPublicKeyWithoutParams(icert.getPublicKey())) {
172            keyParamsNeededFlag = true;
173        }
174
175        /* update certificate */
176        this.cert = icert;
177
178        /* update issuer DN */
179        issuerDN = cert.getIssuerX500Principal();
180
181        if (!X509CertImpl.isSelfIssued(cert)) {
182
183            /*
184             * update traversedCACerts only if this is a non-self-issued
185             * intermediate CA cert
186             */
187            if (!init && cert.getBasicConstraints() != -1) {
188                traversedCACerts++;
189            }
190        }
191
192        /* update subjectNamesTraversed only if this is the EE cert or if
193           this cert is not self-issued */
194        if (init || !X509CertImpl.isSelfIssued(cert)){
195            X500Principal subjName = cert.getSubjectX500Principal();
196            subjectNamesTraversed.add(X500Name.asX500Name(subjName));
197
198            try {
199                SubjectAlternativeNameExtension subjAltNameExt
200                    = icert.getSubjectAlternativeNameExtension();
201                if (subjAltNameExt != null) {
202                    GeneralNames gNames = subjAltNameExt.get(
203                            SubjectAlternativeNameExtension.SUBJECT_NAME);
204                    for (GeneralName gName : gNames.names()) {
205                        subjectNamesTraversed.add(gName.getName());
206                    }
207                }
208            } catch (IOException e) {
209                if (debug != null) {
210                    debug.println("ForwardState.updateState() unexpected "
211                        + "exception");
212                    e.printStackTrace();
213                }
214                throw new CertPathValidatorException(e);
215            }
216        }
217
218        init = false;
219    }
220
221    /*
222     * Clone current state. The state is cloned as each cert is
223     * added to the path. This is necessary if backtracking occurs,
224     * and a prior state needs to be restored.
225     *
226     * Note that this is a SMART clone. Not all fields are fully copied,
227     * because some of them will
228     * not have their contents modified by subsequent calls to updateState.
229     */
230    @Override
231    @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
232    public Object clone() {
233        try {
234            ForwardState clonedState = (ForwardState) super.clone();
235
236            /* clone checkers, if cloneable */
237            clonedState.forwardCheckers = (ArrayList<PKIXCertPathChecker>)
238                                                forwardCheckers.clone();
239            ListIterator<PKIXCertPathChecker> li =
240                                clonedState.forwardCheckers.listIterator();
241            while (li.hasNext()) {
242                PKIXCertPathChecker checker = li.next();
243                if (checker instanceof Cloneable) {
244                    li.set((PKIXCertPathChecker)checker.clone());
245                }
246            }
247
248            /*
249             * Shallow copy traversed names. There is no need to
250             * deep copy contents, since the elements of the Set
251             * are never modified by subsequent calls to updateState().
252             */
253            clonedState.subjectNamesTraversed
254                = (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
255            return clonedState;
256        } catch (CloneNotSupportedException e) {
257            throw new InternalError(e.toString(), e);
258        }
259    }
260}
261