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