verity: Add tools to help OEMs generate signed boot images.
Change-Id: Iea200def2fdd8a0d366888bb7b1ae401297063f1
diff --git a/verity/BootSignature.java b/verity/BootSignature.java
new file mode 100644
index 0000000..f5ceb30
--- /dev/null
+++ b/verity/BootSignature.java
@@ -0,0 +1,124 @@
+/*
+ * 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]);
+ }
+}
\ No newline at end of file