TrustedCertificateIndex.java revision 06fb2e026572e4f67ac80c927d30e9be787bbe6e
106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/* 206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Copyright (C) 2009 The Android Open Source Project 306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * 406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * you may not use this file except in compliance with the License. 606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * You may obtain a copy of the License at 706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * 806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * 1006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Unless required by applicable law or agreed to in writing, software 1106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 1206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * See the License for the specific language governing permissions and 1406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * limitations under the License. 1506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */ 1606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 1706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrompackage org.apache.harmony.xnet.provider.jsse; 1806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 1906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport javax.security.auth.x500.X500Principal; 2006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 2106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPath; 2206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertPathValidatorException; 2306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.CertificateEncodingException; 2406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.PKIXParameters; 2506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.TrustAnchor; 2606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.cert.X509Certificate; 2706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.InvalidAlgorithmParameterException; 2806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.security.KeyStoreException; 2906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.ArrayList; 3006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Arrays; 3106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.HashMap; 3206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.List; 3306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Map; 3406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.Set; 3506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.logging.Logger; 3606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstromimport java.util.logging.Level; 3706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 3806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom/** 3906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Indexes trust anchors so they can be found in O(1) time instead of O(N). 4006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */ 4106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrompublic class IndexedPKIXParameters extends PKIXParameters { 4206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 4306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom final Map<Bytes, TrustAnchor> encodings 4406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom = new HashMap<Bytes, TrustAnchor>(); 4506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom final Map<X500Principal, TrustAnchor> bySubject 4606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom = new HashMap<X500Principal, TrustAnchor>(); 4706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom final Map<X500Principal, List<TrustAnchor>> byCA 4806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom = new HashMap<X500Principal, List<TrustAnchor>>(); 4906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 5006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom public IndexedPKIXParameters(Set<TrustAnchor> anchors) 5106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom throws KeyStoreException, InvalidAlgorithmParameterException, 5206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom CertificateEncodingException { 5306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom super(anchors); 5406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 5506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom for (TrustAnchor anchor : anchors) { 5606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom X509Certificate cert = anchor.getTrustedCert(); 5706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 5806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Bytes encoded = new Bytes(cert.getEncoded()); 5906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom encodings.put(encoded, anchor); 6006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 6106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom X500Principal subject = cert.getSubjectX500Principal(); 6206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (bySubject.put(subject, anchor) != null) { 6306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom // TODO: Should we allow this? 6406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom throw new KeyStoreException("Two certs have the same subject: " 6506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom + subject); 6606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 6706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 6806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom X500Principal ca = anchor.getCA(); 6906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom List<TrustAnchor> caAnchors = byCA.get(ca); 7006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (caAnchors == null) { 7106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom caAnchors = new ArrayList<TrustAnchor>(); 7206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom byCA.put(ca, caAnchors); 7306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 7406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom caAnchors.add(anchor); 7506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 7606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 7706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 7806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom public TrustAnchor findTrustAnchor(X509Certificate cert) 7906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom throws CertPathValidatorException { 8006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom // Mimic the alg in CertPathValidatorUtilities.findTrustAnchor(). 8106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Exception verificationException = null; 8206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom X500Principal issuer = cert.getIssuerX500Principal(); 8306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 8406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom List<TrustAnchor> anchors = byCA.get(issuer); 8506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (anchors != null) { 8606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom for (TrustAnchor caAnchor : anchors) { 8706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom try { 8806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom cert.verify(caAnchor.getCAPublicKey()); 8906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return caAnchor; 9006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } catch (Exception e) { 9106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom verificationException = e; 9206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 9306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 9406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 9506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 9606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom TrustAnchor anchor = bySubject.get(issuer); 9706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (anchor != null) { 9806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom try { 9906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom cert.verify(anchor.getTrustedCert().getPublicKey()); 10006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return anchor; 10106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } catch (Exception e) { 10206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom verificationException = e; 10306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 10406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 10506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 10606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom try { 10706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Bytes encoded = new Bytes(cert.getEncoded()); 10806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom anchor = encodings.get(encoded); 10906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (anchor != null) { 11006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return anchor; 11106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 11206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } catch (Exception e) { 11306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Logger.getLogger(IndexedPKIXParameters.class.getName()).log( 11406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Level.WARNING, "Error encoding cert.", e); 11506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 11606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 11706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom // Throw last verification exception. 11806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom if (verificationException != null) { 11906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom throw new CertPathValidatorException("TrustAnchor found but" 12006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom + " certificate verification failed.", 12106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom verificationException); 12206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 12306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 12406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return null; 12506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 12606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 12706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom /** 12806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Returns true if the given certificate is found in the trusted key 12906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * store. 13006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */ 13106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom public boolean isDirectlyTrusted(X509Certificate cert) { 13206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom try { 13306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Bytes encoded = new Bytes(cert.getEncoded()); 13406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return encodings.containsKey(encoded); 13506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } catch (Exception e) { 13606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Logger.getLogger(IndexedPKIXParameters.class.getName()).log( 13706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Level.WARNING, "Error encoding cert.", e); 13806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return false; 13906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 14006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 14106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom 14206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom /** 14306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom * Wraps a byte[] and adds equals() and hashCode() support. 14406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom */ 14506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom static class Bytes { 14606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom final byte[] bytes; 14706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom final int hash; 14806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom Bytes(byte[] bytes) { 14906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom this.bytes = bytes; 15006fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom this.hash = Arrays.hashCode(bytes); 15106fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 15206fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom @Override public int hashCode() { 15306fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return hash; 15406fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 15506fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom @Override public boolean equals(Object o) { 15606fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom return Arrays.equals(bytes, ((Bytes) o).bytes); 15706fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 15806fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom } 15906fb2e026572e4f67ac80c927d30e9be787bbe6eBrian Carlstrom} 160