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