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