summaryrefslogtreecommitdiffstats
path: root/tools/signapk
diff options
context:
space:
mode:
authorKenny Root <kroot@google.com>2013-09-25 09:59:10 -0700
committerKenny Root <kroot@google.com>2013-09-25 09:59:10 -0700
commit62ea4a5c3cf5da5c64e881e6986e5753304fe8be (patch)
treedf6b5b3143eefcf458348fedbe12ed8148b8ac69 /tools/signapk
parentabc0bf084beea3251c042b28576c8f398749c80b (diff)
downloadbuild-62ea4a5c3cf5da5c64e881e6986e5753304fe8be.zip
build-62ea4a5c3cf5da5c64e881e6986e5753304fe8be.tar.gz
build-62ea4a5c3cf5da5c64e881e6986e5753304fe8be.tar.bz2
Read algorithm OID directly from PKCS#8 container
The PKCS#8 PrivateKeyInfo structure has the algorithm OID encoded right before the actual key octet stream is encoded. Use Bouncycastle to read the OID for creation with the key factory. This aids in the creation of custom key types that are backed by hardware devices (e.g., HSMs) and have their own assigned OIDs. Change-Id: If5d8fe07bc157e9bb5a3fb5f99091e924143105f
Diffstat (limited to 'tools/signapk')
-rw-r--r--tools/signapk/SignApk.java48
1 files changed, 18 insertions, 30 deletions
diff --git a/tools/signapk/SignApk.java b/tools/signapk/SignApk.java
index a1e422c..d4e49e6e 100644
--- a/tools/signapk/SignApk.java
+++ b/tools/signapk/SignApk.java
@@ -20,6 +20,7 @@ import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessableByteArray;
@@ -35,7 +36,7 @@ import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.encoders.Base64;
import java.io.BufferedReader;
-import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
@@ -52,16 +53,13 @@ import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
-import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
@@ -184,7 +182,7 @@ class SignApk {
}
/**
- * Decrypt an encrypted PKCS 8 format private key.
+ * Decrypt an encrypted PKCS#8 format private key.
*
* Based on ghstark's post on Aug 6, 2006 at
* http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949
@@ -192,7 +190,7 @@ class SignApk {
* @param encryptedPrivateKey The raw data of the private key
* @param keyFile The file containing the private key
*/
- private static KeySpec decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile)
+ private static PKCS8EncodedKeySpec decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile)
throws GeneralSecurityException {
EncryptedPrivateKeyInfo epkInfo;
try {
@@ -218,7 +216,7 @@ class SignApk {
}
}
- /** Read a PKCS 8 format private key. */
+ /** Read a PKCS#8 format private key. */
private static PrivateKey readPrivateKey(File file)
throws IOException, GeneralSecurityException {
DataInputStream input = new DataInputStream(new FileInputStream(file));
@@ -226,37 +224,26 @@ class SignApk {
byte[] bytes = new byte[(int) file.length()];
input.read(bytes);
- KeySpec spec = decryptPrivateKey(bytes, file);
+ /* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
+ PKCS8EncodedKeySpec spec = decryptPrivateKey(bytes, file);
if (spec == null) {
spec = new PKCS8EncodedKeySpec(bytes);
}
- PrivateKey key;
- key = decodeAsKeyType(spec, "RSA");
- if (key != null) {
- return key;
- }
-
- key = decodeAsKeyType(spec, "EC");
- if (key != null) {
- return key;
- }
+ /*
+ * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
+ * OID and use that to construct a KeyFactory.
+ */
+ ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
+ PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
+ String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
- throw new NoSuchAlgorithmException("Must be an EC or RSA key");
+ return KeyFactory.getInstance(algOid).generatePrivate(spec);
} finally {
input.close();
}
}
- private static PrivateKey decodeAsKeyType(KeySpec spec, String keyType)
- throws GeneralSecurityException {
- try {
- return KeyFactory.getInstance(keyType).generatePrivate(spec);
- } catch (InvalidKeySpecException e) {
- return null;
- }
- }
-
/**
* Add the hash(es) of every file to the manifest, creating it if
* necessary.
@@ -725,9 +712,10 @@ class SignApk {
outputJar.write(signedData);
// CERT.{EC,RSA} / CERT#.{EC,RSA}
+ final String keyType = publicKey[k].getPublicKey().getAlgorithm();
je = new JarEntry(numKeys == 1 ?
- (String.format(CERT_SIG_NAME, privateKey[k].getAlgorithm())) :
- (String.format(CERT_SIG_MULTI_NAME, k, privateKey[k].getAlgorithm())));
+ (String.format(CERT_SIG_NAME, keyType)) :
+ (String.format(CERT_SIG_MULTI_NAME, k, keyType)));
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureBlock(new CMSProcessableByteArray(signedData),