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 19 import java.io.IOException; 20 import java.security.PrivateKey; 21 import java.util.Arrays; 22 import org.bouncycastle.asn1.ASN1Encodable; 23 import org.bouncycastle.asn1.ASN1EncodableVector; 24 import org.bouncycastle.asn1.ASN1Integer; 25 import org.bouncycastle.asn1.ASN1Object; 26 import org.bouncycastle.asn1.ASN1Primitive; 27 import org.bouncycastle.asn1.DEROctetString; 28 import org.bouncycastle.asn1.DERPrintableString; 29 import org.bouncycastle.asn1.DERSequence; 30 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 31 import org.bouncycastle.asn1.util.ASN1Dump; 32 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 33 34 /** 35 * AndroidVerifiedBootSignature DEFINITIONS ::= 36 * BEGIN 37 * FormatVersion ::= INTEGER 38 * AlgorithmIdentifier ::= SEQUENCE { 39 * algorithm OBJECT IDENTIFIER, 40 * parameters ANY DEFINED BY algorithm OPTIONAL 41 * } 42 * AuthenticatedAttributes ::= SEQUENCE { 43 * target CHARACTER STRING, 44 * length INTEGER 45 * } 46 * Signature ::= OCTET STRING 47 * END 48 */ 49 50 public class BootSignature extends ASN1Object 51 { 52 private ASN1Integer formatVersion; 53 private AlgorithmIdentifier algorithmIdentifier; 54 private DERPrintableString target; 55 private ASN1Integer length; 56 private DEROctetString signature; 57 BootSignature(String target, int length)58 public BootSignature(String target, int length) { 59 this.formatVersion = new ASN1Integer(0); 60 this.target = new DERPrintableString(target); 61 this.length = new ASN1Integer(length); 62 this.algorithmIdentifier = new AlgorithmIdentifier( 63 PKCSObjectIdentifiers.sha256WithRSAEncryption); 64 } 65 getAuthenticatedAttributes()66 public ASN1Object getAuthenticatedAttributes() { 67 ASN1EncodableVector attrs = new ASN1EncodableVector(); 68 attrs.add(target); 69 attrs.add(length); 70 return new DERSequence(attrs); 71 } 72 getEncodedAuthenticatedAttributes()73 public byte[] getEncodedAuthenticatedAttributes() throws IOException { 74 return getAuthenticatedAttributes().getEncoded(); 75 } 76 setSignature(byte[] sig)77 public void setSignature(byte[] sig) { 78 signature = new DEROctetString(sig); 79 } 80 generateSignableImage(byte[] image)81 public byte[] generateSignableImage(byte[] image) throws IOException { 82 byte[] attrs = getEncodedAuthenticatedAttributes(); 83 byte[] signable = Arrays.copyOf(image, image.length + attrs.length); 84 for (int i=0; i < attrs.length; i++) { 85 signable[i+image.length] = attrs[i]; 86 } 87 return signable; 88 } 89 sign(byte[] image, PrivateKey key)90 public byte[] sign(byte[] image, PrivateKey key) throws Exception { 91 byte[] signable = generateSignableImage(image); 92 byte[] signature = Utils.sign(key, signable); 93 byte[] signed = Arrays.copyOf(image, image.length + signature.length); 94 for (int i=0; i < signature.length; i++) { 95 signed[i+image.length] = signature[i]; 96 } 97 return signed; 98 } 99 toASN1Primitive()100 public ASN1Primitive toASN1Primitive() { 101 ASN1EncodableVector v = new ASN1EncodableVector(); 102 v.add(formatVersion); 103 v.add(algorithmIdentifier); 104 v.add(getAuthenticatedAttributes()); 105 v.add(signature); 106 return new DERSequence(v); 107 } 108 doSignature( String target, String imagePath, String keyPath, String outPath)109 public static void doSignature( String target, 110 String imagePath, 111 String keyPath, 112 String outPath) throws Exception { 113 byte[] image = Utils.read(imagePath); 114 BootSignature bootsig = new BootSignature(target, image.length); 115 PrivateKey key = Utils.loadPEMPrivateKeyFromFile(keyPath); 116 byte[] signature = bootsig.sign(image, key); 117 Utils.write(signature, outPath); 118 } 119 120 // java -cp ../../../out/host/common/obj/JAVA_LIBRARIES/AndroidVerifiedBootSigner_intermediates/classes/ com.android.verity.AndroidVerifiedBootSigner boot ../../../out/target/product/flounder/boot.img ../../../build/target/product/security/verity_private_dev_key /tmp/boot.img.signed main(String[] args)121 public static void main(String[] args) throws Exception { 122 doSignature(args[0], args[1], args[2], args[3]); 123 } 124 }