1cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra/*
2cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * Copyright (C) 2014 The Android Open Source Project
3cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *
4cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * Licensed under the Apache License, Version 2.0 (the "License");
5cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * you may not use this file except in compliance with the License.
6cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * You may obtain a copy of the License at
7cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *
8cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *      http://www.apache.org/licenses/LICENSE-2.0
9cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *
10cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * Unless required by applicable law or agreed to in writing, software
11cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * distributed under the License is distributed on an "AS IS" BASIS,
12cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * See the License for the specific language governing permissions and
14cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * limitations under the License.
15cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra */
16cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
17cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condrapackage com.android.verity;
18cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
19cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport java.io.IOException;
20cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport java.security.PrivateKey;
21cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport java.util.Arrays;
22cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Encodable;
23cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1EncodableVector;
24cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Integer;
25cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Object;
26cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Primitive;
27cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DEROctetString;
28cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DERPrintableString;
29cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DERSequence;
30cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
31cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.util.ASN1Dump;
32cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.x509.AlgorithmIdentifier;
33cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
34cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra/**
35cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *    AndroidVerifiedBootSignature DEFINITIONS ::=
36cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *    BEGIN
37cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        FormatVersion ::= INTEGER
38cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        AlgorithmIdentifier ::=  SEQUENCE {
39cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *            algorithm OBJECT IDENTIFIER,
40cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *            parameters ANY DEFINED BY algorithm OPTIONAL
41cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        }
42cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        AuthenticatedAttributes ::= SEQUENCE {
43cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *            target CHARACTER STRING,
44cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *            length INTEGER
45cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        }
46cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *        Signature ::= OCTET STRING
47cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *     END
48cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra */
49cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
50cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condrapublic class BootSignature extends ASN1Object
51cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra{
52cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private ASN1Integer             formatVersion;
53cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private AlgorithmIdentifier     algorithmIdentifier;
54cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private DERPrintableString      target;
55cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private ASN1Integer             length;
56cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private DEROctetString          signature;
57cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
58cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public BootSignature(String target, int length) {
59cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.formatVersion = new ASN1Integer(0);
60cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.target = new DERPrintableString(target);
61cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.length = new ASN1Integer(length);
62cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.algorithmIdentifier = new AlgorithmIdentifier(
63cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                PKCSObjectIdentifiers.sha256WithRSAEncryption);
64cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
65cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
66cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public ASN1Object getAuthenticatedAttributes() {
67cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ASN1EncodableVector attrs = new ASN1EncodableVector();
68cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        attrs.add(target);
69cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        attrs.add(length);
70cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return new DERSequence(attrs);
71cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
72cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
73cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public byte[] getEncodedAuthenticatedAttributes() throws IOException {
74cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return getAuthenticatedAttributes().getEncoded();
75cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
76cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
77cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public void setSignature(byte[] sig) {
78cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        signature = new DEROctetString(sig);
79cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
80cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
81cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public byte[] generateSignableImage(byte[] image) throws IOException {
82cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] attrs = getEncodedAuthenticatedAttributes();
83cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] signable = Arrays.copyOf(image, image.length + attrs.length);
84cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        for (int i=0; i < attrs.length; i++) {
85cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra            signable[i+image.length] = attrs[i];
86cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        }
87cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return signable;
88cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
89cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
90cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public byte[] sign(byte[] image, PrivateKey key) throws Exception {
91cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] signable = generateSignableImage(image);
92cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] signature = Utils.sign(key, signable);
93cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] signed = Arrays.copyOf(image, image.length + signature.length);
94cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        for (int i=0; i < signature.length; i++) {
95cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra            signed[i+image.length] = signature[i];
96cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        }
97cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return signed;
98cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
99cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
100cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public ASN1Primitive toASN1Primitive() {
101cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ASN1EncodableVector v = new ASN1EncodableVector();
102cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(formatVersion);
103cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(algorithmIdentifier);
104cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(getAuthenticatedAttributes());
105cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(signature);
106cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return new DERSequence(v);
107cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
108cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
109cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public static void doSignature( String target,
110cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                                    String imagePath,
111cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                                    String keyPath,
112cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                                    String outPath) throws Exception {
113cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] image = Utils.read(imagePath);
114cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        BootSignature bootsig = new BootSignature(target, image.length);
115cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        PrivateKey key = Utils.loadPEMPrivateKeyFromFile(keyPath);
116cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] signature = bootsig.sign(image, key);
117cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        Utils.write(signature, outPath);
118cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
119cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
120cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    // 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
121cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public static void main(String[] args) throws Exception {
122cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        doSignature(args[0], args[1], args[2], args[3]);
123cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
124cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra}