summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2014-11-14 14:51:25 +0000
committerSami Tolvanen <samitolvanen@google.com>2014-11-17 19:02:26 +0000
commit241f964e10ce8bc6c401073854fdaf1662013dae (patch)
treede74b829ccf04a67604a2ed8ae9217032ebc6dd4
parent40193d94182934b37f4b2ae00fde2402583e59e1 (diff)
downloadextras-241f964e10ce8bc6c401073854fdaf1662013dae.tar.gz
Add signature verification to keystore and verity signers
This change adds -verify flags to keystore and verity signers for verifying the signatures of the signed content generated by the same tools. This allows implementers of verified boot to test and verify the correctness of their implementations. Bug: 15984840 Change-Id: I327de9c3a9e035cd11dc5022e978c840cd37581c
-rw-r--r--verity/BootSignature.java12
-rw-r--r--verity/KeystoreSigner.java98
-rw-r--r--verity/KeystoreSigner.mf2
-rw-r--r--verity/VeritySigner.java47
-rwxr-xr-x[-rw-r--r--]verity/keystore_signer2
5 files changed, 136 insertions, 25 deletions
diff --git a/verity/BootSignature.java b/verity/BootSignature.java
index c45224a7..03eb32a7 100644
--- a/verity/BootSignature.java
+++ b/verity/BootSignature.java
@@ -128,6 +128,18 @@ public class BootSignature extends ASN1Object
return getAuthenticatedAttributes().getEncoded();
}
+ public AlgorithmIdentifier getAlgorithmIdentifier() {
+ return algorithmIdentifier;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public byte[] getSignature() {
+ return signature.getOctets();
+ }
+
public void setSignature(byte[] sig, AlgorithmIdentifier algId) {
algorithmIdentifier = algId;
signature = new DEROctetString(sig);
diff --git a/verity/KeystoreSigner.java b/verity/KeystoreSigner.java
index 3d946a69..0927d548 100644
--- a/verity/KeystoreSigner.java
+++ b/verity/KeystoreSigner.java
@@ -21,11 +21,15 @@ import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;
@@ -63,8 +67,7 @@ class BootKey extends ASN1Object
this.keyMaterial = new RSAPublicKey(
k.getModulus(),
k.getPublicExponent());
- this.algorithmIdentifier = new AlgorithmIdentifier(
- PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ this.algorithmIdentifier = Utils.getSignatureAlgorithmIdentifier(key);
}
public ASN1Primitive toASN1Primitive() {
@@ -81,12 +84,15 @@ class BootKey extends ASN1Object
class BootKeystore extends ASN1Object
{
- private ASN1Integer formatVersion;
- private ASN1EncodableVector keyBag;
- private BootSignature signature;
+ private ASN1Integer formatVersion;
+ private ASN1EncodableVector keyBag;
+ private BootSignature signature;
+ private X509Certificate certificate;
+
+ private static final int FORMAT_VERSION = 0;
public BootKeystore() {
- this.formatVersion = new ASN1Integer(0);
+ this.formatVersion = new ASN1Integer(FORMAT_VERSION);
this.keyBag = new ASN1EncodableVector();
}
@@ -96,6 +102,10 @@ class BootKeystore extends ASN1Object
keyBag.add(k);
}
+ public void setCertificate(X509Certificate cert) {
+ certificate = cert;
+ }
+
public byte[] getInnerKeystore() throws Exception {
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(formatVersion);
@@ -111,10 +121,36 @@ class BootKeystore extends ASN1Object
return new DERSequence(v);
}
+ public void parse(byte[] input) throws Exception {
+ ASN1InputStream stream = new ASN1InputStream(input);
+ ASN1Sequence sequence = (ASN1Sequence) stream.readObject();
+
+ formatVersion = (ASN1Integer) sequence.getObjectAt(0);
+ if (formatVersion.getValue().intValue() != FORMAT_VERSION) {
+ throw new IllegalArgumentException("Unsupported format version");
+ }
+
+ ASN1Sequence keys = (ASN1Sequence) sequence.getObjectAt(1);
+ Enumeration e = keys.getObjects();
+ while (e.hasMoreElements()) {
+ keyBag.add((ASN1Encodable) e.nextElement());
+ }
+
+ ASN1Object sig = sequence.getObjectAt(2).toASN1Primitive();
+ signature = new BootSignature(sig.getEncoded());
+ }
+
+ public boolean verify() throws Exception {
+ byte[] innerKeystore = getInnerKeystore();
+ return Utils.verify(signature.getPublicKey(), innerKeystore,
+ signature.getSignature(), signature.getAlgorithmIdentifier());
+ }
+
public void sign(PrivateKey privateKey) throws Exception {
byte[] innerKeystore = getInnerKeystore();
byte[] rawSignature = Utils.sign(privateKey, innerKeystore);
signature = new BootSignature("keystore", innerKeystore.length);
+ signature.setCertificate(certificate);
signature.setSignature(rawSignature,
Utils.getSignatureAlgorithmIdentifier(privateKey));
}
@@ -123,19 +159,49 @@ class BootKeystore extends ASN1Object
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
+ private static void usage() {
+ System.err.println("usage: KeystoreSigner <privatekey.pk8> " +
+ "<certificate.x509.pem> <outfile> <publickey0.der> " +
+ "... <publickeyN-1.der> | -verify <keystore>");
+ System.exit(1);
+ }
+
public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ usage();
+ return;
+ }
+
Security.addProvider(new BouncyCastleProvider());
- 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]));
+
+ if ("-verify".equals(args[0])) {
+ ks.parse(Utils.read(args[1]));
+
+ try {
+ if (ks.verify()) {
+ System.err.println("Signature is VALID");
+ System.exit(0);
+ } else {
+ System.err.println("Signature is INVALID");
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+ System.exit(1);
+ } else {
+ String privkeyFname = args[0];
+ String certFname = args[1];
+ String outfileFname = args[2];
+
+ ks.setCertificate(Utils.loadPEMCertificate(certFname));
+
+ for (int i = 3; i < args.length; i++) {
+ ks.addPublicKey(Utils.read(args[i]));
+ }
+
+ ks.sign(Utils.loadDERPrivateKeyFromFile(privkeyFname));
+ Utils.write(ks.getEncoded(), outfileFname);
}
- ks.sign(Utils.loadDERPrivateKeyFromFile(privkeyFname));
- Utils.write(ks.getEncoded(), outfileFname);
}
}
diff --git a/verity/KeystoreSigner.mf b/verity/KeystoreSigner.mf
index a4fee27f..472b7c43 100644
--- a/verity/KeystoreSigner.mf
+++ b/verity/KeystoreSigner.mf
@@ -1 +1 @@
-Main-Class: com.android.verity.KeystoreSigner \ No newline at end of file
+Main-Class: com.android.verity.BootKeystore
diff --git a/verity/VeritySigner.java b/verity/VeritySigner.java
index d11878ab..9d857473 100644
--- a/verity/VeritySigner.java
+++ b/verity/VeritySigner.java
@@ -16,21 +16,54 @@
package com.android.verity;
+import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.Security;
+import java.security.cert.X509Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class VeritySigner {
- // USAGE:
- // VeritySigner <contentfile> <key.pem> <sigfile>
- // To verify that this has correct output:
- // openssl rsautl -raw -inkey <key.pem> -encrypt -in <sigfile> > /tmp/dump
+ private static void usage() {
+ System.err.println("usage: VeritySigner <contentfile> <key.pk8> " +
+ "<sigfile> | <contentfile> <certificate.x509.pem> <sigfile> " +
+ "-verify");
+ System.exit(1);
+ }
+
public static void main(String[] args) throws Exception {
+ if (args.length < 3) {
+ usage();
+ return;
+ }
+
Security.addProvider(new BouncyCastleProvider());
+
byte[] content = Utils.read(args[0]);
- PrivateKey privateKey = Utils.loadDERPrivateKey(Utils.read(args[1]));
- byte[] signature = Utils.sign(privateKey, content);
- Utils.write(signature, args[2]);
+
+ if (args.length > 3 && "-verify".equals(args[3])) {
+ X509Certificate cert = Utils.loadPEMCertificate(args[1]);
+ PublicKey publicKey = cert.getPublicKey();
+
+ byte[] signature = Utils.read(args[2]);
+
+ try {
+ if (Utils.verify(publicKey, content, signature,
+ Utils.getSignatureAlgorithmIdentifier(publicKey))) {
+ System.err.println("Signature is VALID");
+ System.exit(0);
+ } else {
+ System.err.println("Signature is INVALID");
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+
+ System.exit(1);
+ } else {
+ PrivateKey privateKey = Utils.loadDERPrivateKey(Utils.read(args[1]));
+ byte[] signature = Utils.sign(privateKey, content);
+ Utils.write(signature, args[2]);
+ }
}
}
diff --git a/verity/keystore_signer b/verity/keystore_signer
index 7619c546..445f0c9c 100644..100755
--- a/verity/keystore_signer
+++ b/verity/keystore_signer
@@ -5,4 +5,4 @@
KEYSTORESIGNER_HOME=`dirname "$0"`
KEYSTORESIGNER_HOME=`dirname "$KEYSTORESIGNER_HOME"`
-java -Xmx512M -jar "$KEYSTORESIGNER_HOME"/framework/KeystoreSigner.jar "$@" \ No newline at end of file
+java -Xmx512M -jar "$KEYSTORESIGNER_HOME"/framework/BootKeystoreSigner.jar "$@"