1*288bf522SAndroid Build Coastguard Worker /* 2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project 3*288bf522SAndroid Build Coastguard Worker * 4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*288bf522SAndroid Build Coastguard Worker * 8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*288bf522SAndroid Build Coastguard Worker * 10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*288bf522SAndroid Build Coastguard Worker * limitations under the License. 15*288bf522SAndroid Build Coastguard Worker */ 16*288bf522SAndroid Build Coastguard Worker 17*288bf522SAndroid Build Coastguard Worker package com.android.verity; 18*288bf522SAndroid Build Coastguard Worker 19*288bf522SAndroid Build Coastguard Worker import java.io.ByteArrayInputStream; 20*288bf522SAndroid Build Coastguard Worker import java.io.IOException; 21*288bf522SAndroid Build Coastguard Worker import java.nio.ByteBuffer; 22*288bf522SAndroid Build Coastguard Worker import java.nio.ByteOrder; 23*288bf522SAndroid Build Coastguard Worker import java.security.PrivateKey; 24*288bf522SAndroid Build Coastguard Worker import java.security.PublicKey; 25*288bf522SAndroid Build Coastguard Worker import java.security.Security; 26*288bf522SAndroid Build Coastguard Worker import java.security.cert.X509Certificate; 27*288bf522SAndroid Build Coastguard Worker import java.security.cert.Certificate; 28*288bf522SAndroid Build Coastguard Worker import java.security.cert.CertificateFactory; 29*288bf522SAndroid Build Coastguard Worker import java.security.cert.CertificateEncodingException; 30*288bf522SAndroid Build Coastguard Worker import java.util.Arrays; 31*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1Encodable; 32*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1EncodableVector; 33*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1Integer; 34*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1Object; 35*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1ObjectIdentifier; 36*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1OctetString; 37*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1Primitive; 38*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1Sequence; 39*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1InputStream; 40*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.DEROctetString; 41*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.DERPrintableString; 42*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.DERSequence; 43*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.util.ASN1Dump; 44*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 45*288bf522SAndroid Build Coastguard Worker import org.bouncycastle.jce.provider.BouncyCastleProvider; 46*288bf522SAndroid Build Coastguard Worker 47*288bf522SAndroid Build Coastguard Worker /** 48*288bf522SAndroid Build Coastguard Worker * AndroidVerifiedBootSignature DEFINITIONS ::= 49*288bf522SAndroid Build Coastguard Worker * BEGIN 50*288bf522SAndroid Build Coastguard Worker * formatVersion ::= INTEGER 51*288bf522SAndroid Build Coastguard Worker * certificate ::= Certificate 52*288bf522SAndroid Build Coastguard Worker * algorithmIdentifier ::= SEQUENCE { 53*288bf522SAndroid Build Coastguard Worker * algorithm OBJECT IDENTIFIER, 54*288bf522SAndroid Build Coastguard Worker * parameters ANY DEFINED BY algorithm OPTIONAL 55*288bf522SAndroid Build Coastguard Worker * } 56*288bf522SAndroid Build Coastguard Worker * authenticatedAttributes ::= SEQUENCE { 57*288bf522SAndroid Build Coastguard Worker * target CHARACTER STRING, 58*288bf522SAndroid Build Coastguard Worker * length INTEGER 59*288bf522SAndroid Build Coastguard Worker * } 60*288bf522SAndroid Build Coastguard Worker * signature ::= OCTET STRING 61*288bf522SAndroid Build Coastguard Worker * END 62*288bf522SAndroid Build Coastguard Worker */ 63*288bf522SAndroid Build Coastguard Worker 64*288bf522SAndroid Build Coastguard Worker public class BootSignature extends ASN1Object 65*288bf522SAndroid Build Coastguard Worker { 66*288bf522SAndroid Build Coastguard Worker private ASN1Integer formatVersion; 67*288bf522SAndroid Build Coastguard Worker private ASN1Encodable certificate; 68*288bf522SAndroid Build Coastguard Worker private AlgorithmIdentifier algorithmIdentifier; 69*288bf522SAndroid Build Coastguard Worker private DERPrintableString target; 70*288bf522SAndroid Build Coastguard Worker private ASN1Integer length; 71*288bf522SAndroid Build Coastguard Worker private DEROctetString signature; 72*288bf522SAndroid Build Coastguard Worker private PublicKey publicKey; 73*288bf522SAndroid Build Coastguard Worker 74*288bf522SAndroid Build Coastguard Worker private static final int FORMAT_VERSION = 1; 75*288bf522SAndroid Build Coastguard Worker /** 76*288bf522SAndroid Build Coastguard Worker * Offset of recovery DTBO length in a boot image header of version greater than 77*288bf522SAndroid Build Coastguard Worker * or equal to 1. 78*288bf522SAndroid Build Coastguard Worker */ 79*288bf522SAndroid Build Coastguard Worker private static final int BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET = 1632; 80*288bf522SAndroid Build Coastguard Worker /** 81*288bf522SAndroid Build Coastguard Worker * Offset of DTB length in a boot image header of version greater than 82*288bf522SAndroid Build Coastguard Worker * or equal to 2. 83*288bf522SAndroid Build Coastguard Worker */ 84*288bf522SAndroid Build Coastguard Worker private static final int BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET = 1648; 85*288bf522SAndroid Build Coastguard Worker 86*288bf522SAndroid Build Coastguard Worker 87*288bf522SAndroid Build Coastguard Worker /** 88*288bf522SAndroid Build Coastguard Worker * Initializes the object for signing an image file 89*288bf522SAndroid Build Coastguard Worker * @param target Target name, included in the signed data 90*288bf522SAndroid Build Coastguard Worker * @param length Length of the image, included in the signed data 91*288bf522SAndroid Build Coastguard Worker */ BootSignature(String target, int length)92*288bf522SAndroid Build Coastguard Worker public BootSignature(String target, int length) { 93*288bf522SAndroid Build Coastguard Worker this.formatVersion = new ASN1Integer(FORMAT_VERSION); 94*288bf522SAndroid Build Coastguard Worker this.target = new DERPrintableString(target); 95*288bf522SAndroid Build Coastguard Worker this.length = new ASN1Integer(length); 96*288bf522SAndroid Build Coastguard Worker } 97*288bf522SAndroid Build Coastguard Worker 98*288bf522SAndroid Build Coastguard Worker /** 99*288bf522SAndroid Build Coastguard Worker * Initializes the object for verifying a signed image file 100*288bf522SAndroid Build Coastguard Worker * @param signature Signature footer 101*288bf522SAndroid Build Coastguard Worker */ BootSignature(byte[] signature)102*288bf522SAndroid Build Coastguard Worker public BootSignature(byte[] signature) 103*288bf522SAndroid Build Coastguard Worker throws Exception { 104*288bf522SAndroid Build Coastguard Worker ASN1InputStream stream = new ASN1InputStream(signature); 105*288bf522SAndroid Build Coastguard Worker ASN1Sequence sequence = (ASN1Sequence) stream.readObject(); 106*288bf522SAndroid Build Coastguard Worker 107*288bf522SAndroid Build Coastguard Worker formatVersion = (ASN1Integer) sequence.getObjectAt(0); 108*288bf522SAndroid Build Coastguard Worker if (formatVersion.getValue().intValue() != FORMAT_VERSION) { 109*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Unsupported format version"); 110*288bf522SAndroid Build Coastguard Worker } 111*288bf522SAndroid Build Coastguard Worker 112*288bf522SAndroid Build Coastguard Worker certificate = sequence.getObjectAt(1); 113*288bf522SAndroid Build Coastguard Worker byte[] encoded = ((ASN1Object) certificate).getEncoded(); 114*288bf522SAndroid Build Coastguard Worker ByteArrayInputStream bis = new ByteArrayInputStream(encoded); 115*288bf522SAndroid Build Coastguard Worker 116*288bf522SAndroid Build Coastguard Worker CertificateFactory cf = CertificateFactory.getInstance("X.509"); 117*288bf522SAndroid Build Coastguard Worker X509Certificate c = (X509Certificate) cf.generateCertificate(bis); 118*288bf522SAndroid Build Coastguard Worker publicKey = c.getPublicKey(); 119*288bf522SAndroid Build Coastguard Worker 120*288bf522SAndroid Build Coastguard Worker ASN1Sequence algId = (ASN1Sequence) sequence.getObjectAt(2); 121*288bf522SAndroid Build Coastguard Worker algorithmIdentifier = new AlgorithmIdentifier( 122*288bf522SAndroid Build Coastguard Worker (ASN1ObjectIdentifier) algId.getObjectAt(0)); 123*288bf522SAndroid Build Coastguard Worker 124*288bf522SAndroid Build Coastguard Worker ASN1Sequence attrs = (ASN1Sequence) sequence.getObjectAt(3); 125*288bf522SAndroid Build Coastguard Worker target = (DERPrintableString) attrs.getObjectAt(0); 126*288bf522SAndroid Build Coastguard Worker length = (ASN1Integer) attrs.getObjectAt(1); 127*288bf522SAndroid Build Coastguard Worker 128*288bf522SAndroid Build Coastguard Worker this.signature = (DEROctetString) sequence.getObjectAt(4); 129*288bf522SAndroid Build Coastguard Worker } 130*288bf522SAndroid Build Coastguard Worker getAuthenticatedAttributes()131*288bf522SAndroid Build Coastguard Worker public ASN1Object getAuthenticatedAttributes() { 132*288bf522SAndroid Build Coastguard Worker ASN1EncodableVector attrs = new ASN1EncodableVector(); 133*288bf522SAndroid Build Coastguard Worker attrs.add(target); 134*288bf522SAndroid Build Coastguard Worker attrs.add(length); 135*288bf522SAndroid Build Coastguard Worker return new DERSequence(attrs); 136*288bf522SAndroid Build Coastguard Worker } 137*288bf522SAndroid Build Coastguard Worker getEncodedAuthenticatedAttributes()138*288bf522SAndroid Build Coastguard Worker public byte[] getEncodedAuthenticatedAttributes() throws IOException { 139*288bf522SAndroid Build Coastguard Worker return getAuthenticatedAttributes().getEncoded(); 140*288bf522SAndroid Build Coastguard Worker } 141*288bf522SAndroid Build Coastguard Worker getAlgorithmIdentifier()142*288bf522SAndroid Build Coastguard Worker public AlgorithmIdentifier getAlgorithmIdentifier() { 143*288bf522SAndroid Build Coastguard Worker return algorithmIdentifier; 144*288bf522SAndroid Build Coastguard Worker } 145*288bf522SAndroid Build Coastguard Worker getPublicKey()146*288bf522SAndroid Build Coastguard Worker public PublicKey getPublicKey() { 147*288bf522SAndroid Build Coastguard Worker return publicKey; 148*288bf522SAndroid Build Coastguard Worker } 149*288bf522SAndroid Build Coastguard Worker getSignature()150*288bf522SAndroid Build Coastguard Worker public byte[] getSignature() { 151*288bf522SAndroid Build Coastguard Worker return signature.getOctets(); 152*288bf522SAndroid Build Coastguard Worker } 153*288bf522SAndroid Build Coastguard Worker setSignature(byte[] sig, AlgorithmIdentifier algId)154*288bf522SAndroid Build Coastguard Worker public void setSignature(byte[] sig, AlgorithmIdentifier algId) { 155*288bf522SAndroid Build Coastguard Worker algorithmIdentifier = algId; 156*288bf522SAndroid Build Coastguard Worker signature = new DEROctetString(sig); 157*288bf522SAndroid Build Coastguard Worker } 158*288bf522SAndroid Build Coastguard Worker setCertificate(X509Certificate cert)159*288bf522SAndroid Build Coastguard Worker public void setCertificate(X509Certificate cert) 160*288bf522SAndroid Build Coastguard Worker throws Exception, IOException, CertificateEncodingException { 161*288bf522SAndroid Build Coastguard Worker ASN1InputStream s = new ASN1InputStream(cert.getEncoded()); 162*288bf522SAndroid Build Coastguard Worker certificate = s.readObject(); 163*288bf522SAndroid Build Coastguard Worker publicKey = cert.getPublicKey(); 164*288bf522SAndroid Build Coastguard Worker } 165*288bf522SAndroid Build Coastguard Worker generateSignableImage(byte[] image)166*288bf522SAndroid Build Coastguard Worker public byte[] generateSignableImage(byte[] image) throws IOException { 167*288bf522SAndroid Build Coastguard Worker byte[] attrs = getEncodedAuthenticatedAttributes(); 168*288bf522SAndroid Build Coastguard Worker byte[] signable = Arrays.copyOf(image, image.length + attrs.length); 169*288bf522SAndroid Build Coastguard Worker for (int i=0; i < attrs.length; i++) { 170*288bf522SAndroid Build Coastguard Worker signable[i+image.length] = attrs[i]; 171*288bf522SAndroid Build Coastguard Worker } 172*288bf522SAndroid Build Coastguard Worker return signable; 173*288bf522SAndroid Build Coastguard Worker } 174*288bf522SAndroid Build Coastguard Worker sign(byte[] image, PrivateKey key)175*288bf522SAndroid Build Coastguard Worker public byte[] sign(byte[] image, PrivateKey key) throws Exception { 176*288bf522SAndroid Build Coastguard Worker byte[] signable = generateSignableImage(image); 177*288bf522SAndroid Build Coastguard Worker return Utils.sign(key, signable); 178*288bf522SAndroid Build Coastguard Worker } 179*288bf522SAndroid Build Coastguard Worker verify(byte[] image)180*288bf522SAndroid Build Coastguard Worker public boolean verify(byte[] image) throws Exception { 181*288bf522SAndroid Build Coastguard Worker if (length.getValue().intValue() != image.length) { 182*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Invalid image length"); 183*288bf522SAndroid Build Coastguard Worker } 184*288bf522SAndroid Build Coastguard Worker 185*288bf522SAndroid Build Coastguard Worker byte[] signable = generateSignableImage(image); 186*288bf522SAndroid Build Coastguard Worker return Utils.verify(publicKey, signable, signature.getOctets(), 187*288bf522SAndroid Build Coastguard Worker algorithmIdentifier); 188*288bf522SAndroid Build Coastguard Worker } 189*288bf522SAndroid Build Coastguard Worker toASN1Primitive()190*288bf522SAndroid Build Coastguard Worker public ASN1Primitive toASN1Primitive() { 191*288bf522SAndroid Build Coastguard Worker ASN1EncodableVector v = new ASN1EncodableVector(); 192*288bf522SAndroid Build Coastguard Worker v.add(formatVersion); 193*288bf522SAndroid Build Coastguard Worker v.add(certificate); 194*288bf522SAndroid Build Coastguard Worker v.add(algorithmIdentifier); 195*288bf522SAndroid Build Coastguard Worker v.add(getAuthenticatedAttributes()); 196*288bf522SAndroid Build Coastguard Worker v.add(signature); 197*288bf522SAndroid Build Coastguard Worker return new DERSequence(v); 198*288bf522SAndroid Build Coastguard Worker } 199*288bf522SAndroid Build Coastguard Worker getSignableImageSize(byte[] data)200*288bf522SAndroid Build Coastguard Worker public static int getSignableImageSize(byte[] data) throws Exception { 201*288bf522SAndroid Build Coastguard Worker if (!Arrays.equals(Arrays.copyOfRange(data, 0, 8), 202*288bf522SAndroid Build Coastguard Worker "ANDROID!".getBytes("US-ASCII"))) { 203*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Invalid image header: missing magic"); 204*288bf522SAndroid Build Coastguard Worker } 205*288bf522SAndroid Build Coastguard Worker 206*288bf522SAndroid Build Coastguard Worker ByteBuffer image = ByteBuffer.wrap(data); 207*288bf522SAndroid Build Coastguard Worker image.order(ByteOrder.LITTLE_ENDIAN); 208*288bf522SAndroid Build Coastguard Worker 209*288bf522SAndroid Build Coastguard Worker image.getLong(); // magic 210*288bf522SAndroid Build Coastguard Worker int kernelSize = image.getInt(); 211*288bf522SAndroid Build Coastguard Worker image.getInt(); // kernel_addr 212*288bf522SAndroid Build Coastguard Worker int ramdskSize = image.getInt(); 213*288bf522SAndroid Build Coastguard Worker image.getInt(); // ramdisk_addr 214*288bf522SAndroid Build Coastguard Worker int secondSize = image.getInt(); 215*288bf522SAndroid Build Coastguard Worker image.getLong(); // second_addr + tags_addr 216*288bf522SAndroid Build Coastguard Worker int pageSize = image.getInt(); 217*288bf522SAndroid Build Coastguard Worker 218*288bf522SAndroid Build Coastguard Worker int length = pageSize // include the page aligned image header 219*288bf522SAndroid Build Coastguard Worker + ((kernelSize + pageSize - 1) / pageSize) * pageSize 220*288bf522SAndroid Build Coastguard Worker + ((ramdskSize + pageSize - 1) / pageSize) * pageSize 221*288bf522SAndroid Build Coastguard Worker + ((secondSize + pageSize - 1) / pageSize) * pageSize; 222*288bf522SAndroid Build Coastguard Worker 223*288bf522SAndroid Build Coastguard Worker int headerVersion = image.getInt(); // boot image header version 224*288bf522SAndroid Build Coastguard Worker if (headerVersion > 0) { 225*288bf522SAndroid Build Coastguard Worker image.position(BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET); 226*288bf522SAndroid Build Coastguard Worker int recoveryDtboLength = image.getInt(); 227*288bf522SAndroid Build Coastguard Worker length += ((recoveryDtboLength + pageSize - 1) / pageSize) * pageSize; 228*288bf522SAndroid Build Coastguard Worker 229*288bf522SAndroid Build Coastguard Worker image.getLong(); // recovery_dtbo address 230*288bf522SAndroid Build Coastguard Worker int headerSize = image.getInt(); 231*288bf522SAndroid Build Coastguard Worker if (headerVersion == 2) { 232*288bf522SAndroid Build Coastguard Worker image.position(BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET); 233*288bf522SAndroid Build Coastguard Worker int dtbLength = image.getInt(); 234*288bf522SAndroid Build Coastguard Worker length += ((dtbLength + pageSize - 1) / pageSize) * pageSize; 235*288bf522SAndroid Build Coastguard Worker image.getLong(); // dtb address 236*288bf522SAndroid Build Coastguard Worker } 237*288bf522SAndroid Build Coastguard Worker if (image.position() != headerSize) { 238*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException( 239*288bf522SAndroid Build Coastguard Worker "Invalid image header: invalid header length"); 240*288bf522SAndroid Build Coastguard Worker } 241*288bf522SAndroid Build Coastguard Worker } 242*288bf522SAndroid Build Coastguard Worker 243*288bf522SAndroid Build Coastguard Worker length = ((length + pageSize - 1) / pageSize) * pageSize; 244*288bf522SAndroid Build Coastguard Worker 245*288bf522SAndroid Build Coastguard Worker if (length <= 0) { 246*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Invalid image header: invalid length"); 247*288bf522SAndroid Build Coastguard Worker } 248*288bf522SAndroid Build Coastguard Worker 249*288bf522SAndroid Build Coastguard Worker return length; 250*288bf522SAndroid Build Coastguard Worker } 251*288bf522SAndroid Build Coastguard Worker doSignature( String target, String imagePath, String keyPath, String certPath, String outPath)252*288bf522SAndroid Build Coastguard Worker public static void doSignature( String target, 253*288bf522SAndroid Build Coastguard Worker String imagePath, 254*288bf522SAndroid Build Coastguard Worker String keyPath, 255*288bf522SAndroid Build Coastguard Worker String certPath, 256*288bf522SAndroid Build Coastguard Worker String outPath) throws Exception { 257*288bf522SAndroid Build Coastguard Worker 258*288bf522SAndroid Build Coastguard Worker byte[] image = Utils.read(imagePath); 259*288bf522SAndroid Build Coastguard Worker int signableSize = getSignableImageSize(image); 260*288bf522SAndroid Build Coastguard Worker 261*288bf522SAndroid Build Coastguard Worker if (signableSize < image.length) { 262*288bf522SAndroid Build Coastguard Worker System.err.println("NOTE: truncating file " + imagePath + 263*288bf522SAndroid Build Coastguard Worker " from " + image.length + " to " + signableSize + " bytes"); 264*288bf522SAndroid Build Coastguard Worker image = Arrays.copyOf(image, signableSize); 265*288bf522SAndroid Build Coastguard Worker } else if (signableSize > image.length) { 266*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Invalid image: too short, expected " + 267*288bf522SAndroid Build Coastguard Worker signableSize + " bytes"); 268*288bf522SAndroid Build Coastguard Worker } 269*288bf522SAndroid Build Coastguard Worker 270*288bf522SAndroid Build Coastguard Worker BootSignature bootsig = new BootSignature(target, image.length); 271*288bf522SAndroid Build Coastguard Worker 272*288bf522SAndroid Build Coastguard Worker X509Certificate cert = Utils.loadPEMCertificate(certPath); 273*288bf522SAndroid Build Coastguard Worker bootsig.setCertificate(cert); 274*288bf522SAndroid Build Coastguard Worker 275*288bf522SAndroid Build Coastguard Worker PrivateKey key = Utils.loadDERPrivateKeyFromFile(keyPath); 276*288bf522SAndroid Build Coastguard Worker bootsig.setSignature(bootsig.sign(image, key), 277*288bf522SAndroid Build Coastguard Worker Utils.getSignatureAlgorithmIdentifier(key)); 278*288bf522SAndroid Build Coastguard Worker 279*288bf522SAndroid Build Coastguard Worker byte[] encoded_bootsig = bootsig.getEncoded(); 280*288bf522SAndroid Build Coastguard Worker byte[] image_with_metadata = Arrays.copyOf(image, image.length + encoded_bootsig.length); 281*288bf522SAndroid Build Coastguard Worker 282*288bf522SAndroid Build Coastguard Worker System.arraycopy(encoded_bootsig, 0, image_with_metadata, 283*288bf522SAndroid Build Coastguard Worker image.length, encoded_bootsig.length); 284*288bf522SAndroid Build Coastguard Worker 285*288bf522SAndroid Build Coastguard Worker Utils.write(image_with_metadata, outPath); 286*288bf522SAndroid Build Coastguard Worker } 287*288bf522SAndroid Build Coastguard Worker verifySignature(String imagePath, String certPath)288*288bf522SAndroid Build Coastguard Worker public static void verifySignature(String imagePath, String certPath) throws Exception { 289*288bf522SAndroid Build Coastguard Worker byte[] image = Utils.read(imagePath); 290*288bf522SAndroid Build Coastguard Worker int signableSize = getSignableImageSize(image); 291*288bf522SAndroid Build Coastguard Worker 292*288bf522SAndroid Build Coastguard Worker if (signableSize >= image.length) { 293*288bf522SAndroid Build Coastguard Worker throw new IllegalArgumentException("Invalid image: not signed"); 294*288bf522SAndroid Build Coastguard Worker } 295*288bf522SAndroid Build Coastguard Worker 296*288bf522SAndroid Build Coastguard Worker byte[] signature = Arrays.copyOfRange(image, signableSize, image.length); 297*288bf522SAndroid Build Coastguard Worker BootSignature bootsig = new BootSignature(signature); 298*288bf522SAndroid Build Coastguard Worker 299*288bf522SAndroid Build Coastguard Worker if (!certPath.isEmpty()) { 300*288bf522SAndroid Build Coastguard Worker System.err.println("NOTE: verifying using public key from " + certPath); 301*288bf522SAndroid Build Coastguard Worker bootsig.setCertificate(Utils.loadPEMCertificate(certPath)); 302*288bf522SAndroid Build Coastguard Worker } 303*288bf522SAndroid Build Coastguard Worker 304*288bf522SAndroid Build Coastguard Worker try { 305*288bf522SAndroid Build Coastguard Worker if (bootsig.verify(Arrays.copyOf(image, signableSize))) { 306*288bf522SAndroid Build Coastguard Worker System.err.println("Signature is VALID"); 307*288bf522SAndroid Build Coastguard Worker System.exit(0); 308*288bf522SAndroid Build Coastguard Worker } else { 309*288bf522SAndroid Build Coastguard Worker System.err.println("Signature is INVALID"); 310*288bf522SAndroid Build Coastguard Worker } 311*288bf522SAndroid Build Coastguard Worker } catch (Exception e) { 312*288bf522SAndroid Build Coastguard Worker e.printStackTrace(System.err); 313*288bf522SAndroid Build Coastguard Worker } 314*288bf522SAndroid Build Coastguard Worker System.exit(1); 315*288bf522SAndroid Build Coastguard Worker } 316*288bf522SAndroid Build Coastguard Worker 317*288bf522SAndroid Build Coastguard Worker /* Example usage for signing a boot image using dev keys: 318*288bf522SAndroid Build Coastguard Worker java -cp \ 319*288bf522SAndroid Build Coastguard Worker ../../../out/host/common/obj/JAVA_LIBRARIES/BootSignature_intermediates/ \ 320*288bf522SAndroid Build Coastguard Worker classes/com.android.verity.BootSignature \ 321*288bf522SAndroid Build Coastguard Worker /boot \ 322*288bf522SAndroid Build Coastguard Worker ../../../out/target/product/$PRODUCT/boot.img \ 323*288bf522SAndroid Build Coastguard Worker ../../../build/target/product/security/verity.pk8 \ 324*288bf522SAndroid Build Coastguard Worker ../../../build/target/product/security/verity.x509.pem \ 325*288bf522SAndroid Build Coastguard Worker /tmp/boot.img.signed 326*288bf522SAndroid Build Coastguard Worker */ main(String[] args)327*288bf522SAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 328*288bf522SAndroid Build Coastguard Worker Security.addProvider(new BouncyCastleProvider()); 329*288bf522SAndroid Build Coastguard Worker 330*288bf522SAndroid Build Coastguard Worker if ("-verify".equals(args[0])) { 331*288bf522SAndroid Build Coastguard Worker String certPath = ""; 332*288bf522SAndroid Build Coastguard Worker 333*288bf522SAndroid Build Coastguard Worker if (args.length >= 4 && "-certificate".equals(args[2])) { 334*288bf522SAndroid Build Coastguard Worker /* args[3] is the path to a public key certificate */ 335*288bf522SAndroid Build Coastguard Worker certPath = args[3]; 336*288bf522SAndroid Build Coastguard Worker } 337*288bf522SAndroid Build Coastguard Worker 338*288bf522SAndroid Build Coastguard Worker /* args[1] is the path to a signed boot image */ 339*288bf522SAndroid Build Coastguard Worker verifySignature(args[1], certPath); 340*288bf522SAndroid Build Coastguard Worker } else { 341*288bf522SAndroid Build Coastguard Worker /* args[0] is the target name, typically /boot 342*288bf522SAndroid Build Coastguard Worker args[1] is the path to a boot image to sign 343*288bf522SAndroid Build Coastguard Worker args[2] is the path to a private key 344*288bf522SAndroid Build Coastguard Worker args[3] is the path to the matching public key certificate 345*288bf522SAndroid Build Coastguard Worker args[4] is the path where to output the signed boot image 346*288bf522SAndroid Build Coastguard Worker */ 347*288bf522SAndroid Build Coastguard Worker doSignature(args[0], args[1], args[2], args[3], args[4]); 348*288bf522SAndroid Build Coastguard Worker } 349*288bf522SAndroid Build Coastguard Worker } 350*288bf522SAndroid Build Coastguard Worker } 351