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