1082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath/*
2082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * Copyright (C) 2015 The Android Open Source Project
3082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath *
4082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License");
5082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * you may not use this file except in compliance with the License.
6082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * You may obtain a copy of the License at
7082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath *
8082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath *      http://www.apache.org/licenses/LICENSE-2.0
9082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath *
10082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * Unless required by applicable law or agreed to in writing, software
11082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS,
12082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * See the License for the specific language governing permissions and
14082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath * limitations under the License
15082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath */
16082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
17082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathpackage libcore.util;
18082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
19082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport sun.security.pkcs.PKCS7;
20082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport sun.security.pkcs.SignerInfo;
21082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
22082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.io.IOException;
23082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.io.InputStream;
24082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.security.NoSuchAlgorithmException;
25082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.security.PublicKey;
26082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.security.SignatureException;
27082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.security.cert.X509Certificate;
28082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathimport java.util.Set;
29082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
30082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamathpublic class RecoverySystem {
31082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath    private RecoverySystem() {
32082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath    }
33082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
34082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath    /**
35082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath     * Verifies that the signature computed from {@code contentStream} matches
36082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath     * that specified in {@code blockStream}. The public key of the certificates specified
37082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath     * in the PCKS7 block must match
38082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath     */
39082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath    public static void verify(InputStream blockStream, InputStream contentStream,
40082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath                              Set<X509Certificate> trustedCerts)
41082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            throws IOException, SignatureException, NoSuchAlgorithmException {
42082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        PKCS7 block = new PKCS7(blockStream);
43082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
44082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        // Take the first certificate from the signature (packages
45082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        // should contain only one).
46082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        X509Certificate[] certificates = block.getCertificates();
47082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        if (certificates == null || certificates.length == 0) {
48082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            throw new SignatureException("signature contains no certificates");
49082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        }
50082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        X509Certificate cert = certificates[0];
51082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        PublicKey signatureKey = cert.getPublicKey();
52082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
53082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        SignerInfo[] signerInfos = block.getSignerInfos();
54082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        if (signerInfos == null || signerInfos.length == 0) {
55082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            throw new SignatureException("signature contains no signedData");
56082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        }
57082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        SignerInfo signerInfo = signerInfos[0];
58082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
59082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        boolean verified = false;
60082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        for (X509Certificate c : trustedCerts) {
61082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            if (c.getPublicKey().equals(signatureKey)) {
62082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath                verified = true;
63082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath                break;
64082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            }
65082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        }
66082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
67082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        if (!verified) {
68082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            throw new SignatureException("signature doesn't match any trusted key");
69082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        }
70082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath
71082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        SignerInfo verifyResult = block.verify(signerInfo, contentStream);
72082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        if (verifyResult == null) {
73082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath            throw new SignatureException("signature digest verification failed");
74082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath        }
75082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath    }
76082643a27088b8dbae15c0e084ce319d0346636aNarayan Kamath}
77