Skip to content

Commit d2c220f

Browse files
committed
Move closer to validating whole android cert chain
1 parent 4a829b6 commit d2c220f

4 files changed

Lines changed: 55 additions & 17 deletions

File tree

u2f-ref-code/java/src/com/google/u2f/server/impl/attestation/android/AndroidKeyStoreAttestation.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ private AndroidKeyStoreAttestation(Integer keymasterVersion, byte[] attestationC
4949
}
5050

5151
/**
52-
* Parses the key description extension. Expected format is:
52+
* Parses the key description extension. Note that this method only parses the description
53+
* extension in the leaf cert. It *does not* validate the certificate (or any chain).
54+
*
55+
* TODO(aczeskis): Add chain validation and remove/clarify the above comment.
56+
*
57+
* Expected format of the description extension is:
5358
* KeyDescription ::= SEQUENCE {
5459
* keymasterVersion INTEGER,
5560
* attestationChallenge OCTET_STRING,

u2f-ref-code/java/tests/com/google/u2f/TestUtils.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66

77
package com.google.u2f;
88

9+
import org.apache.commons.codec.DecoderException;
10+
import org.apache.commons.codec.binary.Base64;
11+
import org.apache.commons.codec.binary.Hex;
12+
import org.bouncycastle.asn1.sec.SECNamedCurves;
13+
import org.bouncycastle.asn1.x9.X9ECParameters;
14+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
15+
import org.bouncycastle.jce.spec.ECParameterSpec;
16+
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
17+
import org.bouncycastle.jce.spec.ECPublicKeySpec;
18+
import org.bouncycastle.math.ec.ECPoint;
19+
920
import java.io.ByteArrayInputStream;
1021
import java.math.BigInteger;
1122
import java.security.KeyFactory;
@@ -14,21 +25,12 @@
1425
import java.security.PrivateKey;
1526
import java.security.PublicKey;
1627
import java.security.Security;
28+
import java.security.cert.Certificate;
1729
import java.security.cert.CertificateException;
1830
import java.security.cert.CertificateFactory;
1931
import java.security.cert.X509Certificate;
2032
import java.security.spec.InvalidKeySpecException;
21-
22-
import org.apache.commons.codec.DecoderException;
23-
import org.apache.commons.codec.binary.Hex;
24-
import org.apache.commons.codec.binary.Base64;
25-
import org.bouncycastle.asn1.sec.SECNamedCurves;
26-
import org.bouncycastle.asn1.x9.X9ECParameters;
27-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
28-
import org.bouncycastle.jce.spec.ECParameterSpec;
29-
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
30-
import org.bouncycastle.jce.spec.ECPublicKeySpec;
31-
import org.bouncycastle.math.ec.ECPoint;
33+
import java.util.Collection;
3234

3335
public class TestUtils {
3436

@@ -65,6 +67,17 @@ public static X509Certificate parseCertificateBase64(String encodedDerCertificat
6567
return parseCertificate(parseBase64(encodedDerCertificate));
6668
}
6769

70+
public static X509Certificate[] parseCertificateChainBase64(String encodedDerCertificates) {
71+
try {
72+
Collection<? extends Certificate> certCollection =
73+
CertificateFactory.getInstance("X.509").generateCertificates(
74+
new ByteArrayInputStream(parseBase64(encodedDerCertificates)));
75+
return certCollection.toArray(new X509Certificate[0]);
76+
} catch (CertificateException e) {
77+
throw new RuntimeException(e);
78+
}
79+
}
80+
6881
public static PrivateKey parsePrivateKey(String keyBytesHex) {
6982
try {
7083
KeyFactory fac = KeyFactory.getInstance("ECDSA");

u2f-ref-code/java/tests/com/google/u2f/TestVectors.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static com.google.u2f.TestUtils.computeSha256;
1010
import static com.google.u2f.TestUtils.parseCertificate;
1111
import static com.google.u2f.TestUtils.parseCertificateBase64;
12+
import static com.google.u2f.TestUtils.parseCertificateChainBase64;
1213
import static com.google.u2f.TestUtils.parseHex;
1314
import static com.google.u2f.TestUtils.parsePrivateKey;
1415
import static com.google.u2f.TestUtils.parsePublicKey;
@@ -315,17 +316,36 @@ public class TestVectors {
315316
protected static final X509Certificate ANDROID_KEYSTORE_ATTESTATION_CERT_NO_VERSION =
316317
parseCertificateBase64(ANDROID_KEYSTORE_ATTESTATION_CERT_NO_VERSION_BASE64);
317318

318-
private static final String ANDROID_KEYSTORE_ATTESTATION_CERT_BASE64 =
319+
/**
320+
* Contains a chain where:
321+
* cert[0] = attestation certificate describing some new key
322+
* cert[1] = batch certificate
323+
*
324+
* Note that cert[1] is signed by another cert that should be known to RPs.
325+
*/
326+
private static final String ANDROID_KEYSTORE_ATTESTATION_CERT_CHAIN_BASE64 =
319327
"MIIBjTCCATKgAwIBAgICJxAwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAwwRQW5kcm9pZCBLZXltYXN0"
320328
+ "ZXIwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMBoxGDAWBgNVBAMMD0EgS2V5bWFz"
321329
+ "dGVyIEtleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJiTI/rSw9N1NYV3FGxgeJSj1NWyyb61"
322330
+ "/gbdEefKuM3dYOeUZhciSigDY/u9Y3gBKm0wmXsd7DxXibDk/VvGIVWjZDBiMGAGCisGAQQB1nkC"
323331
+ "AREEUjBQAgECBAljaGFsbGVuZ2UwPqEIMQYCAQICAQOiAwIBA6MEAgIBAKUFMQMCAQS/g3gDAgEB"
324332
+ "v4N5BAICASy/hT0IAgYBUqi8MmC/hT4DAgEAMAAwCgYIKoZIzj0EAwIDSQAwRgIhANnmsSeWsnVH"
325333
+ "aF5zII50tkiA7fRhIMNeZZBcPvSV2BN5AiEAwUZm63OxMZEHTIFL50ASKVN/sCLs8+gMY6uEVZRy"
326-
+ "61Q=";
327-
protected static final X509Certificate ANDROID_KEYSTORE_ATTESTATION_CERT =
328-
parseCertificateBase64(ANDROID_KEYSTORE_ATTESTATION_CERT_BASE64);
334+
+ "61QwggK2MIICH6ADAgECAgIQADANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzETMBEGA1UE"
335+
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UECgwMR29vZ2xlLCBJ"
336+
+ "bmMuMRAwDgYDVQQLDAdBbmRyb2lkMB4XDTE2MDEwNDEyNDA1M1oXDTM1MTIzMDEyNDA1M1owdjEL"
337+
+ "MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAoMDEdvb2dsZSwgSW5jLjEQ"
338+
+ "MA4GA1UECwwHQW5kcm9pZDEpMCcGA1UEAwwgQW5kcm9pZCBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBL"
339+
+ "ZXkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCDI9xWiBu4MCBp9bCFYcbuvn8F4vWoQgSK"
340+
+ "votHvnb+rvJc8psq+jIAFBYBQpmJoV/PxoFes2NYPC/S8gvkmDKD3YFLFtfhhUF65Uq8KWo6bbXA"
341+
+ "BAg7aMVWwfAjOZFkGYZNULdNQK7KSEx3NWyJWgwnWr+sSZ1dfSNi8pxeAuhxAgMBAAGjZjBkMB0G"
342+
+ "A1UdDgQWBBTUDBAb+M1jufc5UrUOE1ym15mThjAfBgNVHSMEGDAWgBQp+vGszE3STJZAJ3W2sOky"
343+
+ "5Qf+LjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIChDANBgkqhkiG9w0BAQsFAAOB"
344+
+ "gQCeLUhfjGcz3BqFrZnXUCPqFOxDsOGd6sIjRh5ytRncYCLkpWgxbAtVxOacoi2fOk+TazGLFngW"
345+
+ "DYjL2YvMgJ2E8MIn42s48f3R5xdyMVk1fZbzxX+rnY+WYSZPsr6Buw1JBCKKzp/39UIuJUT6IQcS"
346+
+ "WoO1Va0YgvhAFJucIGMEfw==";
347+
protected static final X509Certificate[] ANDROID_KEYSTORE_ATTESTATION_CERT_CHAIN =
348+
parseCertificateChainBase64(ANDROID_KEYSTORE_ATTESTATION_CERT_CHAIN_BASE64);
329349

330350
protected static final byte[] REGISTRATION_DATA_2 =
331351
parseHex("0504478E16BBDBBB741A660A000314A8B6BD63095196ED704C52EEBC0FA02A61"

u2f-ref-code/java/tests/com/google/u2f/server/impl/attestation/android/AndroidKeyStoreAttestationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class AndroidKeyStoreAttestationTest extends TestVectors {
2121
@Test
2222
public void testValidCert() throws Exception {
2323
AndroidKeyStoreAttestation attestation =
24-
AndroidKeyStoreAttestation.Parse(ANDROID_KEYSTORE_ATTESTATION_CERT);
24+
AndroidKeyStoreAttestation.Parse(ANDROID_KEYSTORE_ATTESTATION_CERT_CHAIN[0]);
2525

2626
assertNotNull("Not expecting null attestation", attestation);
2727

0 commit comments

Comments
 (0)