| /* |
| * 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, |
| new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption)); |
| } |
| |
| 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); |
| } |
| } |