/*
* 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.security.PublicKey;
import java.security.Signature;
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.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
/**
* AndroidVerifiedBootKeystore DEFINITIONS ::=
* BEGIN
* FormatVersion ::= INTEGER
* KeyBag ::= SEQUENCE {
* Key ::= SEQUENCE {
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL
* }
* KeyMaterial ::= RSAPublicKey
* }
* }
* Signature ::= AndroidVerifiedBootSignature
* END
*/
class BootKey extends ASN1Object
{
private AlgorithmIdentifier algorithmIdentifier;
private RSAPublicKey keyMaterial;
public BootKey(PublicKey key) throws Exception {
java.security.interfaces.RSAPublicKey k =
(java.security.interfaces.RSAPublicKey) key;
this.keyMaterial = new RSAPublicKey(
k.getModulus(),
k.getPublicExponent());
this.algorithmIdentifier = new AlgorithmIdentifier(
PKCSObjectIdentifiers.sha256WithRSAEncryption);
}
public ASN1Primitive toASN1Primitive() {
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(algorithmIdentifier);
v.add(keyMaterial);
return new DERSequence(v);
}
public void dump() throws Exception {
System.out.println(ASN1Dump.dumpAsString(toASN1Primitive()));
}
}
class BootKeystore extends ASN1Object
{
private ASN1Integer formatVersion;
private ASN1EncodableVector keyBag;
private BootSignature signature;
public BootKeystore() {
this.formatVersion = new ASN1Integer(0);
this.keyBag = new ASN1EncodableVector();
}
public void addPublicKey(byte[] der) throws Exception {
PublicKey pubkey = Utils.loadDERPublicKey(der);
BootKey k = new BootKey(pubkey);
keyBag.add(k);
}
public byte[] getInnerKeystore() throws Exception {
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(formatVersion);
v.add(new DERSequence(keyBag));
return new DERSequence(v).getEncoded();
}
public ASN1Primitive toASN1Primitive() {
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(formatVersion);
v.add(new DERSequence(keyBag));
v.add(signature);
return new DERSequence(v);
}
public void sign(PrivateKey privateKey) throws Exception {
byte[] innerKeystore = getInnerKeystore();
byte[] rawSignature = Utils.sign(privateKey, innerKeystore);
signature = new BootSignature("keystore", innerKeystore.length);
signature.setSignature(rawSignature);
}
public void dump() throws Exception {
System.out.println(ASN1Dump.dumpAsString(toASN1Primitive()));
}
// USAGE:
// AndroidVerifiedBootKeystoreSigner <privkeyFile> <outfile> <pubkeyFile0> ... <pubkeyFileN-1>
// EG:
// 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
public static void main(String[] args) throws Exception {
String privkeyFname = args[0];
String outfileFname = args[1];
BootKeystore ks = new BootKeystore();
for (int i=2; i < args.length; i++) {
ks.addPublicKey(Utils.read(args[i]));
}
ks.sign(Utils.loadPEMPrivateKeyFromFile(privkeyFname));
Utils.write(ks.getEncoded(), outfileFname);
}
}