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.security.PublicKey;
22cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport java.security.Signature;
23cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Encodable;
24cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1EncodableVector;
25cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Integer;
26cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Object;
27cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.ASN1Primitive;
28cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DEROctetString;
29cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DERPrintableString;
30cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.DERSequence;
31cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
32cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.pkcs.RSAPublicKey;
33cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.util.ASN1Dump;
34cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraimport org.bouncycastle.asn1.x509.AlgorithmIdentifier;
35cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
36cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra/**
37cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * AndroidVerifiedBootKeystore DEFINITIONS ::=
38cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * BEGIN
39cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *     FormatVersion ::= INTEGER
40cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *     KeyBag ::= SEQUENCE {
41cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *         Key  ::= SEQUENCE {
42cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *             AlgorithmIdentifier  ::=  SEQUENCE {
43cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *                 algorithm OBJECT IDENTIFIER,
44cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *                 parameters ANY DEFINED BY algorithm OPTIONAL
45cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *             }
46cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *             KeyMaterial ::= RSAPublicKey
47cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *         }
48cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *     }
49cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra *     Signature ::= AndroidVerifiedBootSignature
50cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra * END
51cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra */
52cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
53cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraclass BootKey extends ASN1Object
54cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra{
55cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private AlgorithmIdentifier algorithmIdentifier;
56cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private RSAPublicKey keyMaterial;
57cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
58cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public BootKey(PublicKey key) throws Exception {
59cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        java.security.interfaces.RSAPublicKey k =
60cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                (java.security.interfaces.RSAPublicKey) key;
61cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.keyMaterial = new RSAPublicKey(
62cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                k.getModulus(),
63cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                k.getPublicExponent());
64cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.algorithmIdentifier = new AlgorithmIdentifier(
65cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra                PKCSObjectIdentifiers.sha256WithRSAEncryption);
66cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
67cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
68cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public ASN1Primitive toASN1Primitive() {
69cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ASN1EncodableVector v = new ASN1EncodableVector();
70cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(algorithmIdentifier);
71cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(keyMaterial);
72cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return new DERSequence(v);
73cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
74cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
75cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public void dump() throws Exception {
76cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        System.out.println(ASN1Dump.dumpAsString(toASN1Primitive()));
77cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
78cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra}
79cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
80cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condraclass BootKeystore extends ASN1Object
81cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra{
82cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private ASN1Integer                     formatVersion;
83cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private ASN1EncodableVector             keyBag;
84cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    private BootSignature    signature;
85cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
86cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public BootKeystore() {
87cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.formatVersion = new ASN1Integer(0);
88cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        this.keyBag = new ASN1EncodableVector();
89cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
90cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
91cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public void addPublicKey(byte[] der) throws Exception {
92cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        PublicKey pubkey = Utils.loadDERPublicKey(der);
93cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        BootKey k = new BootKey(pubkey);
94cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        keyBag.add(k);
95cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
96cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
97cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public byte[] getInnerKeystore() throws Exception {
98cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ASN1EncodableVector v = new ASN1EncodableVector();
99cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(formatVersion);
100cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(new DERSequence(keyBag));
101cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return new DERSequence(v).getEncoded();
102cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
103cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
104cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public ASN1Primitive toASN1Primitive() {
105cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ASN1EncodableVector v = new ASN1EncodableVector();
106cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(formatVersion);
107cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(new DERSequence(keyBag));
108cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        v.add(signature);
109cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        return new DERSequence(v);
110cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
111cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
112cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public void sign(PrivateKey privateKey) throws Exception {
113cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] innerKeystore = getInnerKeystore();
114cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        byte[] rawSignature = Utils.sign(privateKey, innerKeystore);
115cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        signature = new BootSignature("keystore", innerKeystore.length);
116cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        signature.setSignature(rawSignature);
117cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
118cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
119cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public void dump() throws Exception {
120cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        System.out.println(ASN1Dump.dumpAsString(toASN1Primitive()));
121cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
122cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra
123cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    // USAGE:
124cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    //      AndroidVerifiedBootKeystoreSigner <privkeyFile> <outfile> <pubkeyFile0> ... <pubkeyFileN-1>
125cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    // EG:
126cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    //     java -cp ../../../out/host/common/obj/JAVA_LIBRARIES/AndroidVerifiedBootKeystoreSigner_intermediates/classes/ com.android.verity.AndroidVerifiedBootKeystoreSigner ../../../build/target/product/security/verity_private_dev_key /tmp/keystore.out /tmp/k
127cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    public static void main(String[] args) throws Exception {
128cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        String privkeyFname = args[0];
129cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        String outfileFname = args[1];
130cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        BootKeystore ks = new BootKeystore();
131cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        for (int i=2; i < args.length; i++) {
132cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra            ks.addPublicKey(Utils.read(args[i]));
133cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        }
134cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        ks.sign(Utils.loadPEMPrivateKeyFromFile(privkeyFname));
135cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra        Utils.write(ks.getEncoded(), outfileFname);
136cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra    }
137cee5bfdf119104b8ebce56d54dfcdcca1f537075Geremy Condra}