The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | * contributor license agreements. See the NOTICE file distributed with |
| 4 | * this work for additional information regarding copyright ownership. |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | * (the "License"); you may not use this file except in compliance with |
| 7 | * the License. You may obtain a copy of the License at |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | /** |
| 19 | * @author Alexander Y. Kleymenov |
| 20 | * @version $Revision$ |
| 21 | */ |
| 22 | |
| 23 | package org.apache.harmony.security.provider.cert; |
| 24 | |
| 25 | import java.io.IOException; |
| 26 | import java.io.InputStream; |
| 27 | import java.security.cert.CertPath; |
| 28 | import java.security.cert.CertificateEncodingException; |
| 29 | import java.security.cert.CertificateException; |
| 30 | import java.security.cert.X509Certificate; |
| 31 | import java.util.ArrayList; |
| 32 | import java.util.Arrays; |
| 33 | import java.util.Collection; |
| 34 | import java.util.Collections; |
| 35 | import java.util.Iterator; |
| 36 | import java.util.List; |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 37 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 38 | import org.apache.harmony.security.asn1.ASN1Any; |
| 39 | import org.apache.harmony.security.asn1.ASN1Explicit; |
| 40 | import org.apache.harmony.security.asn1.ASN1Implicit; |
| 41 | import org.apache.harmony.security.asn1.ASN1Oid; |
| 42 | import org.apache.harmony.security.asn1.ASN1Sequence; |
| 43 | import org.apache.harmony.security.asn1.ASN1SequenceOf; |
| 44 | import org.apache.harmony.security.asn1.ASN1Type; |
| 45 | import org.apache.harmony.security.asn1.BerInputStream; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 46 | import org.apache.harmony.security.pkcs7.ContentInfo; |
| 47 | import org.apache.harmony.security.pkcs7.SignedData; |
| 48 | import org.apache.harmony.security.x509.Certificate; |
| 49 | |
| 50 | /** |
| 51 | * This class is an implementation of X.509 CertPath. This implementation |
| 52 | * provides ability to create the instance of X.509 Certification Path |
| 53 | * by several means:<br> |
| 54 | * |
| 55 | * 1. It can be created over the list of X.509 certificates |
| 56 | * (implementations of X509Certificate class) provided in constructor.<br> |
| 57 | * |
| 58 | * 2. It can be created by means of <code>getInstance</code> methods |
| 59 | * on the base of the following ASN.1 DER encoded forms:<br> |
| 60 | * |
| 61 | * - PkiPath as defined in |
| 62 | * ITU-T Recommendation X.509(2000) Corrigendum 1(2001) |
| 63 | * (can be seen at |
| 64 | * ftp://ftp.bull.com/pub/OSIdirectory/DefectResolution/TechnicalCorrigenda/ApprovedTechnicalCorrigendaToX.509/8%7CX.509-TC1(4th).pdf) |
| 65 | * <br> |
| 66 | * - PKCS #7 SignedData object provided in the form of |
| 67 | * ContentInfo structure. CertPath object is generated on the base of |
| 68 | * certificates presented in <code>certificates</code> field of the SignedData |
| 69 | * object which in its turn is retrieved from ContentInfo structure. |
| 70 | * (see http://www.ietf.org/rfc/rfc2315.txt |
| 71 | * for more info on PKCS #7) |
| 72 | * <br> |
| 73 | * |
| 74 | */ |
| 75 | public class X509CertPathImpl extends CertPath { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 76 | /** |
| 77 | * @serial |
| 78 | */ |
| 79 | private static final long serialVersionUID = 7989755106209515436L; |
| 80 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 81 | /** |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 82 | * Supported encoding types for CerthPath. Used by the various APIs that |
| 83 | * encode this into bytes such as {@link #getEncoded()}. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 84 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 85 | private enum Encoding { |
| 86 | PKI_PATH("PkiPath"), |
| 87 | PKCS7("PKCS7"); |
| 88 | |
| 89 | private final String apiName; |
| 90 | |
| 91 | Encoding(String apiName) { |
| 92 | this.apiName = apiName; |
| 93 | } |
| 94 | |
| 95 | static Encoding findByApiName(String apiName) throws CertificateEncodingException { |
| 96 | for (Encoding element : values()) { |
| 97 | if (element.apiName.equals(apiName)) { |
| 98 | return element; |
| 99 | } |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 100 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 101 | |
| 102 | return null; |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 103 | } |
| 104 | } |
| 105 | |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 106 | /** Unmodifiable list of encodings for the API. */ |
| 107 | static final List<String> encodings = Collections.unmodifiableList(Arrays.asList(new String[] { |
| 108 | Encoding.PKI_PATH.apiName, |
| 109 | Encoding.PKCS7.apiName, |
| 110 | })); |
| 111 | |
| 112 | /** The list of certificates in the order of target toward trust anchor. */ |
| 113 | private final List<X509Certificate> certificates; |
| 114 | |
| 115 | /** PkiPath encoding of the certification path. */ |
| 116 | private byte[] pkiPathEncoding; |
| 117 | |
| 118 | /** PKCS7 encoding of the certification path. */ |
| 119 | private byte[] pkcs7Encoding; |
| 120 | |
| 121 | /** |
| 122 | * Creates an instance of X.509 CertPath over the specified list of |
| 123 | * certificates. |
| 124 | * |
| 125 | * @throws CertificateException if some of the object in the list is not an |
| 126 | * instance of subclass of X509Certificate. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 127 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 128 | public X509CertPathImpl(List<? extends java.security.cert.Certificate> certs) |
| 129 | throws CertificateException { |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 130 | super("X.509"); |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 131 | |
| 132 | final int size = certs.size(); |
| 133 | certificates = new ArrayList<X509Certificate>(size); |
| 134 | |
| 135 | for (int i = 0; i < size; i++) { |
| 136 | final java.security.cert.Certificate cert = certs.get(i); |
| 137 | if (!(cert instanceof X509Certificate)) { |
| 138 | throw new CertificateException("Certificate " + i + " is not an X.509 certificate"); |
| 139 | } |
| 140 | |
| 141 | certificates.add((X509Certificate) cert); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 142 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | /** |
| 146 | * Creates an X.509 CertPath over the specified {@code certs}. The |
| 147 | * {@code certs} should be sorted correctly when calling into the |
| 148 | * constructor. Additionally, the {@code encodedPath} should match the |
| 149 | * expected output for the {@code type} of encoding. |
| 150 | */ |
| 151 | private X509CertPathImpl(List<X509Certificate> certs, Encoding type) { |
| 152 | super("X.509"); |
| 153 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 154 | certificates = certs; |
| 155 | } |
| 156 | |
| 157 | /** |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 158 | * Extract a CertPath from a PKCS#7 {@code contentInfo} object. |
| 159 | */ |
| 160 | private static X509CertPathImpl getCertPathFromContentInfo(ContentInfo contentInfo) |
| 161 | throws CertificateException { |
| 162 | final SignedData sd = contentInfo.getSignedData(); |
| 163 | if (sd == null) { |
| 164 | throw new CertificateException("Incorrect PKCS7 encoded form: missing signed data"); |
| 165 | } |
| 166 | |
| 167 | List<Certificate> certs = sd.getCertificates(); |
| 168 | if (certs == null) { |
| 169 | certs = Collections.emptyList(); |
| 170 | } |
| 171 | |
| 172 | final List<X509Certificate> result = new ArrayList<X509Certificate>(certs.size()); |
| 173 | for (Certificate cert : certs) { |
| 174 | result.add(new X509CertImpl(cert)); |
| 175 | } |
| 176 | |
| 177 | return new X509CertPathImpl(result, Encoding.PKCS7); |
| 178 | } |
| 179 | |
| 180 | /** |
| 181 | * Generates certification path object on the base of PkiPath encoded form |
| 182 | * provided via input stream. |
| 183 | * |
| 184 | * @throws CertificateException if some problems occurred during the |
| 185 | * decoding. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 186 | */ |
Brian Carlstrom | 9ff0e55 | 2010-10-20 11:54:07 -0700 | [diff] [blame] | 187 | public static X509CertPathImpl getInstance(InputStream in) throws CertificateException { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 188 | try { |
| 189 | return (X509CertPathImpl) ASN1.decode(in); |
| 190 | } catch (IOException e) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 191 | throw new CertificateException("Failed to decode CertPath", e); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 192 | } |
| 193 | } |
| 194 | |
| 195 | /** |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 196 | * Generates certification path object on the basis of encoding provided via |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 197 | * input stream. The format of provided encoded form is specified by |
| 198 | * parameter <code>encoding</code>. |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 199 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 200 | * @throws CertificateException if specified encoding form is not supported, |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 201 | * or some problems occurred during the decoding. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 202 | */ |
| 203 | public static X509CertPathImpl getInstance(InputStream in, String encoding) |
Brian Carlstrom | 9ff0e55 | 2010-10-20 11:54:07 -0700 | [diff] [blame] | 204 | throws CertificateException { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 205 | try { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 206 | final Encoding encType = Encoding.findByApiName(encoding); |
| 207 | if (encType == null) { |
| 208 | throw new CertificateException("Unsupported encoding: " + encoding); |
| 209 | } |
| 210 | |
| 211 | switch (encType) { |
| 212 | case PKI_PATH: |
| 213 | return (X509CertPathImpl) ASN1.decode(in); |
| 214 | case PKCS7: |
| 215 | return getCertPathFromContentInfo((ContentInfo) ContentInfo.ASN1.decode(in)); |
| 216 | default: |
| 217 | throw new CertificateException("Unsupported encoding: " + encoding); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 218 | } |
| 219 | } catch (IOException e) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 220 | throw new CertificateException("Failed to decode CertPath", e); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 221 | } |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * Generates certification path object on the base of PkiPath |
| 226 | * encoded form provided via array of bytes. |
| 227 | * @throws CertificateException if some problems occurred during |
| 228 | * the decoding. |
| 229 | */ |
Brian Carlstrom | 9ff0e55 | 2010-10-20 11:54:07 -0700 | [diff] [blame] | 230 | public static X509CertPathImpl getInstance(byte[] in) throws CertificateException { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 231 | try { |
| 232 | return (X509CertPathImpl) ASN1.decode(in); |
| 233 | } catch (IOException e) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 234 | throw new CertificateException("Failed to decode CertPath", e); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 235 | } |
| 236 | } |
| 237 | |
| 238 | /** |
| 239 | * Generates certification path object on the base of encoding provided via |
| 240 | * array of bytes. The format of provided encoded form is specified by |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 241 | * parameter {@code encoding}. |
| 242 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 243 | * @throws CertificateException if specified encoding form is not supported, |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 244 | * or some problems occurred during the decoding. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 245 | */ |
| 246 | public static X509CertPathImpl getInstance(byte[] in, String encoding) |
Brian Carlstrom | 9ff0e55 | 2010-10-20 11:54:07 -0700 | [diff] [blame] | 247 | throws CertificateException { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 248 | try { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 249 | final Encoding encType = Encoding.findByApiName(encoding); |
| 250 | if (encType == null) { |
| 251 | throw new CertificateException("Unsupported encoding: " + encoding); |
| 252 | } |
| 253 | |
| 254 | switch (encType) { |
| 255 | case PKI_PATH: |
| 256 | return (X509CertPathImpl) ASN1.decode(in); |
| 257 | case PKCS7: |
| 258 | return getCertPathFromContentInfo((ContentInfo) ContentInfo.ASN1.decode(in)); |
| 259 | default: |
| 260 | throw new CertificateException("Unsupported encoding: " + encoding); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 261 | } |
| 262 | } catch (IOException e) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 263 | throw new CertificateException("Failed to decode CertPath", e); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 264 | } |
| 265 | } |
| 266 | |
| 267 | // --------------------------------------------------------------------- |
| 268 | // ---- java.security.cert.CertPath abstract method implementations ---- |
| 269 | // --------------------------------------------------------------------- |
| 270 | |
| 271 | /** |
| 272 | * @see java.security.cert.CertPath#getCertificates() |
| 273 | * method documentation for more info |
| 274 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 275 | @Override |
| 276 | public List<X509Certificate> getCertificates() { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 277 | return Collections.unmodifiableList(certificates); |
| 278 | } |
| 279 | |
| 280 | /** |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 281 | * Returns in PkiPath format which is our default encoding. |
| 282 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 283 | * @see java.security.cert.CertPath#getEncoded() |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 284 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 285 | @Override |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 286 | public byte[] getEncoded() throws CertificateEncodingException { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 287 | return getEncoded(Encoding.PKI_PATH); |
| 288 | } |
| 289 | |
| 290 | /** |
| 291 | * @see #getEncoded(String) |
| 292 | */ |
| 293 | private byte[] getEncoded(Encoding encoding) throws CertificateEncodingException { |
| 294 | switch (encoding) { |
| 295 | case PKI_PATH: |
| 296 | if (pkiPathEncoding == null) { |
| 297 | pkiPathEncoding = ASN1.encode(this); |
| 298 | } |
| 299 | |
| 300 | return pkiPathEncoding.clone(); |
| 301 | case PKCS7: |
| 302 | if (pkcs7Encoding == null) { |
| 303 | pkcs7Encoding = PKCS7_SIGNED_DATA_OBJECT.encode(this); |
| 304 | } |
| 305 | |
| 306 | return pkcs7Encoding.clone(); |
| 307 | default: |
| 308 | throw new CertificateEncodingException("Unsupported encoding: " + encoding); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 309 | } |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | /** |
| 313 | * @see java.security.cert.CertPath#getEncoded(String) |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 314 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 315 | @Override |
Elliott Hughes | 897538a | 2010-05-28 20:00:47 -0700 | [diff] [blame] | 316 | public byte[] getEncoded(String encoding) throws CertificateEncodingException { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 317 | final Encoding encType = Encoding.findByApiName(encoding); |
| 318 | if (encType == null) { |
| 319 | throw new CertificateEncodingException("Unsupported encoding: " + encoding); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 320 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 321 | |
| 322 | return getEncoded(encType); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | /** |
| 326 | * @see java.security.cert.CertPath#getEncodings() |
| 327 | * method documentation for more info |
| 328 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 329 | @Override |
| 330 | public Iterator<String> getEncodings() { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 331 | return encodings.iterator(); |
| 332 | } |
| 333 | |
| 334 | /** |
| 335 | * ASN.1 DER Encoder/Decoder for PkiPath structure. |
| 336 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 337 | public static final ASN1SequenceOf ASN1 = new ASN1SequenceOf(ASN1Any.getInstance()) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 338 | /** |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 339 | * Builds the instance of X509CertPathImpl on the base of the list of |
| 340 | * ASN.1 encodings of X.509 certificates provided via PkiPath structure. |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 341 | * This method participates in decoding process. |
| 342 | */ |
| 343 | public Object getDecodedObject(BerInputStream in) throws IOException { |
| 344 | // retrieve the decoded content |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 345 | final List<byte[]> encodedCerts = (List<byte[]>) in.content; |
| 346 | |
| 347 | final int size = encodedCerts.size(); |
| 348 | final List<X509Certificate> certificates = new ArrayList<X509Certificate>(size); |
| 349 | |
| 350 | for (int i = size - 1; i >= 0; i--) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 351 | // create the X.509 certificate on the base of its encoded form |
| 352 | // and add it to the list. |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 353 | certificates.add(new X509CertImpl((Certificate) Certificate.ASN1 |
| 354 | .decode(encodedCerts.get(i)))); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 355 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 356 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 357 | // create and return the resulting object |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 358 | return new X509CertPathImpl(certificates, Encoding.PKI_PATH); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 359 | } |
| 360 | |
| 361 | /** |
| 362 | * Returns the Collection of the encoded form of certificates contained |
| 363 | * in the X509CertPathImpl object to be encoded. |
| 364 | * This method participates in encoding process. |
| 365 | */ |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 366 | public Collection<byte[]> getValues(Object object) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 367 | // object to be encoded |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 368 | final X509CertPathImpl cp = (X509CertPathImpl) object; |
| 369 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 370 | // if it has no certificates in it - create the sequence of size 0 |
| 371 | if (cp.certificates == null) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 372 | return Collections.emptyList(); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 373 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 374 | |
| 375 | final int size = cp.certificates.size(); |
| 376 | final List<byte[]> encodings = new ArrayList<byte[]>(size); |
| 377 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 378 | try { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 379 | for (int i = size - 1; i >= 0; i--) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 380 | // get the encoded form of certificate and place it into the |
| 381 | // list to be encoded in PkiPath format |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 382 | encodings.add(cp.certificates.get(i).getEncoded()); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 383 | } |
| 384 | } catch (CertificateEncodingException e) { |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 385 | throw new IllegalArgumentException("Encoding error occurred", e); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 386 | } |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 387 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 388 | return encodings; |
| 389 | } |
| 390 | }; |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 391 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 392 | |
Kenny Root | 8c6714a | 2013-02-21 15:11:03 -0800 | [diff] [blame] | 393 | /** |
| 394 | * Encoder for PKCS#7 SignedData. It is assumed that only certificate field |
| 395 | * is important all other fields contain pre-calculated encodings. |
| 396 | */ |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 397 | private static final ASN1Sequence ASN1_SIGNED_DATA = new ASN1Sequence( |
| 398 | new ASN1Type[] { |
| 399 | // version ,digestAlgorithms, content info |
| 400 | ASN1Any.getInstance(), |
| 401 | // certificates |
| 402 | new ASN1Implicit(0, ASN1), |
| 403 | // set of crls is optional and is missed here |
| 404 | ASN1Any.getInstance(),// signers info |
| 405 | }) { |
| 406 | |
| 407 | // precalculated ASN.1 encodings for |
| 408 | // version ,digestAlgorithms, content info field of SignedData |
| 409 | private final byte[] PRECALCULATED_HEAD = new byte[] { 0x02, 0x01, |
| 410 | 0x01,// version (v1) |
| 411 | 0x31, 0x00,// empty set of DigestAlgorithms |
| 412 | 0x30, 0x03, 0x06, 0x01, 0x00 // empty ContentInfo with oid=0 |
| 413 | }; |
| 414 | |
| 415 | // precalculated empty set of SignerInfos |
| 416 | private final byte[] SIGNERS_INFO = new byte[] { 0x31, 0x00 }; |
| 417 | |
| 418 | protected void getValues(Object object, Object[] values) { |
| 419 | values[0] = PRECALCULATED_HEAD; |
| 420 | values[1] = object; // pass X509CertPathImpl object |
| 421 | values[2] = SIGNERS_INFO; |
| 422 | } |
| 423 | |
| 424 | // stub to prevent using the instance as decoder |
| 425 | public Object decode(BerInputStream in) throws IOException { |
| 426 | throw new RuntimeException( |
| 427 | "Invalid use of encoder for PKCS#7 SignedData object"); |
| 428 | } |
| 429 | }; |
Elliott Hughes | f33eae7 | 2010-05-13 12:36:25 -0700 | [diff] [blame] | 430 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 431 | private static final ASN1Sequence PKCS7_SIGNED_DATA_OBJECT = new ASN1Sequence( |
| 432 | new ASN1Type[] { ASN1Any.getInstance(), // contentType |
| 433 | new ASN1Explicit(0, ASN1_SIGNED_DATA) // SignedData |
| 434 | }) { |
| 435 | |
| 436 | // precalculated ASN.1 encoding for SignedData object oid |
| 437 | private final byte[] SIGNED_DATA_OID = ASN1Oid.getInstance().encode( |
| 438 | ContentInfo.SIGNED_DATA); |
| 439 | |
| 440 | protected void getValues(Object object, Object[] values) { |
| 441 | values[0] = SIGNED_DATA_OID; |
| 442 | values[1] = object; // pass X509CertPathImpl object |
| 443 | } |
| 444 | |
| 445 | // stub to prevent using the instance as decoder |
| 446 | public Object decode(BerInputStream in) throws IOException { |
| 447 | throw new RuntimeException( |
| 448 | "Invalid use of encoder for PKCS#7 SignedData object"); |
| 449 | } |
| 450 | }; |
| 451 | } |