/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.verity; import java.io.IOException; import java.security.PrivateKey; import java.util.Arrays; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; /** * AndroidVerifiedBootSignature DEFINITIONS ::= * BEGIN * FormatVersion ::= INTEGER * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * AuthenticatedAttributes ::= SEQUENCE { * target CHARACTER STRING, * length INTEGER * } * Signature ::= OCTET STRING * END */ public class BootSignature extends ASN1Object { private ASN1Integer formatVersion; private AlgorithmIdentifier algorithmIdentifier; private DERPrintableString target; private ASN1Integer length; private DEROctetString signature; public BootSignature(String target, int length) { this.formatVersion = new ASN1Integer(0); this.target = new DERPrintableString(target); this.length = new ASN1Integer(length); this.algorithmIdentifier = new AlgorithmIdentifier( PKCSObjectIdentifiers.sha256WithRSAEncryption); } public ASN1Object getAuthenticatedAttributes() { ASN1EncodableVector attrs = new ASN1EncodableVector(); attrs.add(target); attrs.add(length); return new DERSequence(attrs); } public byte[] getEncodedAuthenticatedAttributes() throws IOException { return getAuthenticatedAttributes().getEncoded(); } public void setSignature(byte[] sig) { signature = new DEROctetString(sig); } public byte[] generateSignableImage(byte[] image) throws IOException { byte[] attrs = getEncodedAuthenticatedAttributes(); byte[] signable = Arrays.copyOf(image, image.length + attrs.length); for (int i=0; i < attrs.length; i++) { signable[i+image.length] = attrs[i]; } return signable; } public byte[] sign(byte[] image, PrivateKey key) throws Exception { byte[] signable = generateSignableImage(image); byte[] signature = Utils.sign(key, signable); byte[] signed = Arrays.copyOf(image, image.length + signature.length); for (int i=0; i < signature.length; i++) { signed[i+image.length] = signature[i]; } return signed; } public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); v.add(formatVersion); v.add(algorithmIdentifier); v.add(getAuthenticatedAttributes()); v.add(signature); return new DERSequence(v); } public static void doSignature( String target, String imagePath, String keyPath, String outPath) throws Exception { byte[] image = Utils.read(imagePath); BootSignature bootsig = new BootSignature(target, image.length); PrivateKey key = Utils.loadPEMPrivateKeyFromFile(keyPath); byte[] signature = bootsig.sign(image, key); Utils.write(signature, outPath); } // 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 public static void main(String[] args) throws Exception { doSignature(args[0], args[1], args[2], args[3]); } }