Skip to content

Commit 5423e68

Browse files
committed
Add signing to keystore
Change the keystore to keep the private keys in keystore. When returned, it uses the OpenSSL representation of the key to allow users to use it in various operations through the OpenSSL ENGINE that connects to keystore. Change-Id: I3681f98cb2ec49ffc4a49f3821909313b4ab5735
1 parent b2e822f commit 5423e68

File tree

5 files changed

+352
-17
lines changed

5 files changed

+352
-17
lines changed

keystore/java/android/security/Credentials.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
import java.io.ByteArrayOutputStream;
2727
import java.io.IOException;
2828
import java.io.InputStreamReader;
29+
import java.io.ObjectOutputStream;
2930
import java.io.OutputStreamWriter;
3031
import java.io.Reader;
3132
import java.io.Writer;
3233
import java.nio.charset.Charsets;
3334
import java.security.KeyPair;
35+
import java.security.cert.X509Certificate;
3436
import java.util.ArrayList;
3537
import java.util.List;
3638

@@ -72,6 +74,36 @@ public class Credentials {
7274
public static final String EXTENSION_CER = ".cer";
7375
public static final String EXTENSION_PFX = ".pfx";
7476

77+
/**
78+
* Intent extra: name for the user's private key.
79+
*/
80+
public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name";
81+
82+
/**
83+
* Intent extra: data for the user's private key in PEM-encoded PKCS#8.
84+
*/
85+
public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
86+
87+
/**
88+
* Intent extra: name for the user's certificate.
89+
*/
90+
public static final String EXTRA_USER_CERTIFICATE_NAME = "user_certificate_name";
91+
92+
/**
93+
* Intent extra: data for the user's certificate in PEM-encoded X.509.
94+
*/
95+
public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data";
96+
97+
/**
98+
* Intent extra: name for CA certificate chain
99+
*/
100+
public static final String EXTRA_CA_CERTIFICATES_NAME = "ca_certificates_name";
101+
102+
/**
103+
* Intent extra: data for CA certificate chain in PEM-encoded X.509.
104+
*/
105+
public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data";
106+
75107
/**
76108
* Convert objects to a PEM format, which is used for
77109
* CA_CERTIFICATE, USER_CERTIFICATE, and USER_PRIVATE_KEY

keystore/java/android/security/IKeyChainService.aidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ package android.security;
2323
*/
2424
interface IKeyChainService {
2525
// APIs used by KeyChain
26-
byte[] getPrivateKey(String alias);
26+
String requestPrivateKey(String alias);
2727
byte[] getCertificate(String alias);
2828

2929
// APIs used by CertInstaller

keystore/java/android/security/KeyChain.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.io.ByteArrayInputStream;
2828
import java.io.Closeable;
2929
import java.io.IOException;
30+
import java.security.InvalidKeyException;
3031
import java.security.KeyPair;
3132
import java.security.Principal;
3233
import java.security.PrivateKey;
@@ -39,6 +40,8 @@
3940
import java.util.concurrent.BlockingQueue;
4041
import java.util.concurrent.LinkedBlockingQueue;
4142
import libcore.util.Objects;
43+
44+
import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
4245
import org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore;
4346

4447
/**
@@ -301,14 +304,21 @@ public static PrivateKey getPrivateKey(Context context, String alias)
301304
}
302305
KeyChainConnection keyChainConnection = bind(context);
303306
try {
304-
IKeyChainService keyChainService = keyChainConnection.getService();
305-
byte[] privateKeyBytes = keyChainService.getPrivateKey(alias);
306-
return toPrivateKey(privateKeyBytes);
307+
final IKeyChainService keyChainService = keyChainConnection.getService();
308+
final String keyId = keyChainService.requestPrivateKey(alias);
309+
if (keyId == null) {
310+
throw new KeyChainException("keystore had a problem");
311+
}
312+
313+
final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
314+
return engine.getPrivateKeyById(keyId);
307315
} catch (RemoteException e) {
308316
throw new KeyChainException(e);
309317
} catch (RuntimeException e) {
310318
// only certain RuntimeExceptions can be propagated across the IKeyChainService call
311319
throw new KeyChainException(e);
320+
} catch (InvalidKeyException e) {
321+
throw new KeyChainException(e);
312322
} finally {
313323
keyChainConnection.close();
314324
}
@@ -356,18 +366,6 @@ public static X509Certificate[] getCertificateChain(Context context, String alia
356366
}
357367
}
358368

359-
private static PrivateKey toPrivateKey(byte[] bytes) {
360-
if (bytes == null) {
361-
throw new IllegalArgumentException("bytes == null");
362-
}
363-
try {
364-
KeyPair keyPair = (KeyPair) Credentials.convertFromPem(bytes).get(0);
365-
return keyPair.getPrivate();
366-
} catch (IOException e) {
367-
throw new AssertionError(e);
368-
}
369-
}
370-
371369
private static X509Certificate toCertificate(byte[] bytes) {
372370
if (bytes == null) {
373371
throw new IllegalArgumentException("bytes == null");

keystore/java/android/security/KeyStore.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,78 @@ public boolean isEmpty() {
155155
return mError == KEY_NOT_FOUND;
156156
}
157157

158+
private boolean generate(byte[] key) {
159+
execute('a', key);
160+
return mError == NO_ERROR;
161+
}
162+
163+
public boolean generate(String key) {
164+
return generate(getBytes(key));
165+
}
166+
167+
private boolean importKey(byte[] keyName, byte[] key) {
168+
execute('m', keyName, key);
169+
return mError == NO_ERROR;
170+
}
171+
172+
public boolean importKey(String keyName, byte[] key) {
173+
return importKey(getBytes(keyName), key);
174+
}
175+
176+
private byte[] getPubkey(byte[] key) {
177+
ArrayList<byte[]> values = execute('b', key);
178+
return (values == null || values.isEmpty()) ? null : values.get(0);
179+
}
180+
181+
public byte[] getPubkey(String key) {
182+
return getPubkey(getBytes(key));
183+
}
184+
185+
private boolean delKey(byte[] key) {
186+
execute('k', key);
187+
return mError == NO_ERROR;
188+
}
189+
190+
public boolean delKey(String key) {
191+
return delKey(getBytes(key));
192+
}
193+
194+
private byte[] sign(byte[] keyName, byte[] data) {
195+
final ArrayList<byte[]> values = execute('n', keyName, data);
196+
return (values == null || values.isEmpty()) ? null : values.get(0);
197+
}
198+
199+
public byte[] sign(String key, byte[] data) {
200+
return sign(getBytes(key), data);
201+
}
202+
203+
private boolean verify(byte[] keyName, byte[] data, byte[] signature) {
204+
execute('v', keyName, data, signature);
205+
return mError == NO_ERROR;
206+
}
207+
208+
public boolean verify(String key, byte[] data, byte[] signature) {
209+
return verify(getBytes(key), data, signature);
210+
}
211+
212+
private boolean grant(byte[] key, byte[] uid) {
213+
execute('x', key, uid);
214+
return mError == NO_ERROR;
215+
}
216+
217+
public boolean grant(String key, int uid) {
218+
return grant(getBytes(key), Integer.toString(uid).getBytes());
219+
}
220+
221+
private boolean ungrant(byte[] key, byte[] uid) {
222+
execute('y', key, uid);
223+
return mError == NO_ERROR;
224+
}
225+
226+
public boolean ungrant(String key, int uid) {
227+
return ungrant(getBytes(key), Integer.toString(uid).getBytes());
228+
}
229+
158230
public int getLastError() {
159231
return mError;
160232
}

0 commit comments

Comments
 (0)