OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / harmony / security / utils / JarUtils.java
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 Boris Kuznetsov
20 * @version $Revision$
21 */
22 package org.apache.harmony.security.utils;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.math.BigInteger;
27 import java.security.GeneralSecurityException;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.Principal;
31 import java.security.Signature;
32 import java.security.cert.Certificate;
33 import java.security.cert.X509Certificate;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Iterator;
37 import java.util.LinkedList;
38 import java.util.List;
39 import javax.security.auth.x500.X500Principal;
40 import org.apache.harmony.security.asn1.BerInputStream;
41 import org.apache.harmony.security.pkcs7.ContentInfo;
42 import org.apache.harmony.security.pkcs7.SignedData;
43 import org.apache.harmony.security.pkcs7.SignerInfo;
44 import org.apache.harmony.security.provider.cert.X509CertImpl;
45 import org.apache.harmony.security.x501.AttributeTypeAndValue;
46 import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
47
48 public class JarUtils {
49
50     // as defined in PKCS #9: Selected Attribute Types:
51     // http://www.ietf.org/rfc/rfc2985.txt
52     private static final int[] MESSAGE_DIGEST_OID =
53         new int[] {1, 2, 840, 113549, 1, 9, 4};
54
55     /**
56      * This method handle all the work with  PKCS7, ASN1 encoding, signature verifying,
57      * and certification path building.
58      * See also PKCS #7: Cryptographic Message Syntax Standard:
59      * http://www.ietf.org/rfc/rfc2315.txt
60      * @param signature - the input stream of signature file to be verified
61      * @param signatureBlock - the input stream of corresponding signature block file
62      * @return array of certificates used to verify the signature file
63      * @throws IOException - if some errors occurs during reading from the stream
64      * @throws GeneralSecurityException - if signature verification process fails
65      */
66     public static Certificate[] verifySignature(InputStream signature, InputStream
67             signatureBlock) throws IOException, GeneralSecurityException {
68
69         BerInputStream bis = new BerInputStream(signatureBlock);
70         ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);
71         SignedData signedData = info.getSignedData();
72         if (signedData == null) {
73             throw new IOException("No SignedData found");
74         }
75         Collection encCerts = signedData.getCertificates();
76         if (encCerts.isEmpty()) {
77             return null;
78         }
79         X509Certificate[] certs = new X509Certificate[encCerts.size()];
80         int i = 0;
81         for (Iterator it = encCerts.iterator(); it.hasNext();) {
82             certs[i++]= new X509CertImpl((org.apache.harmony.security.x509.Certificate)it.next());
83         }
84
85         List sigInfos = signedData.getSignerInfos();
86         SignerInfo sigInfo;
87         if (!sigInfos.isEmpty()) {
88             sigInfo = (SignerInfo)sigInfos.get(0);
89         } else {
90             return null;
91         }
92
93         // Issuer
94         X500Principal issuer = sigInfo.getIssuer();
95
96         // Certificate serial number
97         BigInteger snum = sigInfo.getSerialNumber();
98
99         // Locate the certificate
100         int issuerSertIndex = 0;
101         for (i = 0; i < certs.length; i++) {
102             if (issuer.equals(certs[i].getIssuerDN()) &&
103                     snum.equals(certs[i].getSerialNumber())) {
104                 issuerSertIndex = i;
105                 break;
106             }
107         }
108         if (i == certs.length) { // No issuer certificate found
109             return null;
110         }
111
112         if (certs[issuerSertIndex].hasUnsupportedCriticalExtension()) {
113             throw new SecurityException("Can not recognize a critical extension");
114         }
115
116         // Get Signature instance
117         Signature sig = null;
118         String da = sigInfo.getdigestAlgorithm();
119         String dea = sigInfo.getDigestEncryptionAlgorithm();
120         String alg = null;
121         if (da != null && dea != null) {
122             alg = da + "with" +  dea;
123             try{
124                 // BEGIN android-removed
125                 // sig = OpenSSLSignature.getInstance(alg);
126                 // END android-removed
127                 // BEGIN android-added
128                 sig = OpenSSLSignature.getInstance(alg);
129                 // END android-removed
130             } catch (NoSuchAlgorithmException e) {}
131         }
132         if (sig == null) {
133             alg = da;
134             if (alg == null) {
135                 return null;
136             }
137             try{
138                 // BEGIN android-removed
139                 // sig = OpenSSLSignature.getInstance(alg);
140                 // END android-removed
141                 // BEGIN android-added
142                 sig = OpenSSLSignature.getInstance(alg);
143                 // END android-removed
144             } catch (NoSuchAlgorithmException e) {
145                 return null;
146             }
147         }
148         sig.initVerify(certs[issuerSertIndex]);
149
150         // If the authenticatedAttributes field of SignerInfo contains more than zero attributes,
151         // compute the message digest on the ASN.1 DER encoding of the Attributes value.
152         // Otherwise, compute the message digest on the data.
153         List atr = sigInfo.getAuthenticatedAttributes();
154
155         byte[] sfBytes = new byte[signature.available()];
156         signature.read(sfBytes);
157
158         if (atr == null) {
159             sig.update(sfBytes);
160         } else {
161             sig.update(sigInfo.getEncodedAuthenticatedAttributes());
162
163             // If the authenticatedAttributes field contains the message-digest attribute,
164             // verify that it equals the computed digest of the signature file
165             byte[] existingDigest = null;
166             for (Iterator it = atr.iterator(); it.hasNext();) {
167                 AttributeTypeAndValue a = (AttributeTypeAndValue)it.next();
168                 if (Arrays.equals(a.getType().getOid(), MESSAGE_DIGEST_OID) ){
169 //TODO value                    existingDigest = a.AttributeValue;
170                 }
171             }
172             if (existingDigest != null) {
173                 MessageDigest md = MessageDigest.getInstance(sigInfo.getDigestAlgorithm());
174                 byte[] computedDigest = md.digest(sfBytes);
175                 if (!Arrays.equals(existingDigest, computedDigest)) {
176                     throw new SecurityException("Incorrect MD");
177                 }
178             }
179         }
180
181         if (!sig.verify(sigInfo.getEncryptedDigest())) {
182             throw new SecurityException("Incorrect signature");
183         }
184
185         return createChain(certs[issuerSertIndex], certs);
186     }
187
188     private static X509Certificate[] createChain(X509Certificate  signer, X509Certificate[] candidates) {
189         LinkedList chain = new LinkedList();
190         chain.add(0, signer);
191
192         // Signer is self-signed
193         if (signer.getSubjectDN().equals(signer.getIssuerDN())){
194             return (X509Certificate[])chain.toArray(new X509Certificate[1]);
195         }
196
197         Principal issuer = signer.getIssuerDN();
198         X509Certificate issuerCert;
199         int count = 1;
200         while (true) {
201             issuerCert = findCert(issuer, candidates);
202             if( issuerCert == null) {
203                 break;
204             }
205             chain.add(issuerCert);
206             count++;
207             if (issuerCert.getSubjectDN().equals(issuerCert.getIssuerDN())) {
208                 break;
209             }
210             issuer = issuerCert.getIssuerDN();
211         }
212         return (X509Certificate[])chain.toArray(new X509Certificate[count]);
213     }
214
215     private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) {
216         for (int i = 0; i < candidates.length; i++) {
217             if (issuer.equals(candidates[i].getSubjectDN())) {
218                 return candidates[i];
219             }
220         }
221         return null;
222     }
223
224 }