identity: Fix buildSessionTranscript() from a zero leading P-256 EC Public Key.

Properly encode an sessiontranscript from P-256 EC Public Key, in
particular ensure that the resulting sessiontranscript which includes an valid P-256 EC public key is expected.

Was able to reproduce this with about 1% failures running a test.
After the fix didn't get a failure in 1,000 runs.

This bug is similar with AOSP patch "identity: Fix uncompressed form encoding of P-256 EC Public Key."

Bug: 239857653
Test: atest --rerun-until-failure 1000  android.security.identity.cts.ReaderAuthTest#readerAuth
Change-Id: Id5ce46977cf3b6ce6c43beda657cd26b24969fe5
This commit is contained in:
Joseph Jang 2022-07-25 12:08:44 +00:00
parent af43ae73f9
commit e678b870a2
2 changed files with 62 additions and 14 deletions

View file

@ -145,14 +145,38 @@ public class Iso18013 {
// encoded DeviceEngagement
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
// X and Y are always positive so for interop we remove any leading zeroes
// inserted by the BigInteger encoder.
byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray());
byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray());
baos.write(new byte[]{41});
baos.write(x);
baos.write(y);
ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
// Each coordinate may be encoded in 33*, 32, or fewer bytes.
//
// * : it can be 33 bytes because toByteArray() guarantees "The array will contain the
// minimum number of bytes required to represent this BigInteger, including at
// least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that
// the MSB is always 0x00. This is taken care of by calling calling
// stripLeadingZeroes().
//
// We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2
// and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y
// where X and Y are encoded in exactly 32 byte, big endian integer values each.
//
byte[] xBytes = stripLeadingZeroes(w.getAffineX().toByteArray());
if (xBytes.length > 32) {
throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected");
}
for (int n = 0; n < 32 - xBytes.length; n++) {
baos.write(0x00);
}
baos.write(xBytes);
byte[] yBytes = stripLeadingZeroes(w.getAffineY().toByteArray());
if (yBytes.length > 32) {
throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected");
}
for (int n = 0; n < 32 - yBytes.length; n++) {
baos.write(0x00);
}
baos.write(yBytes);
baos.write(new byte[]{42, 44});
} catch (IOException e) {
e.printStackTrace();

View file

@ -1141,14 +1141,38 @@ Certificate:
// encoded DeviceEngagement
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
// X and Y are always positive so for interop we remove any leading zeroes
// inserted by the BigInteger encoder.
byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray());
byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray());
baos.write(new byte[]{42});
baos.write(x);
baos.write(y);
ECPoint w = ((ECPublicKey) ephemeralKeyPair.getPublic()).getW();
// Each coordinate may be encoded in 33*, 32, or fewer bytes.
//
// * : it can be 33 bytes because toByteArray() guarantees "The array will contain the
// minimum number of bytes required to represent this BigInteger, including at
// least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that
// the MSB is always 0x00. This is taken care of by calling calling
// stripLeadingZeroes().
//
// We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2
// and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y
// where X and Y are encoded in exactly 32 byte, big endian integer values each.
//
byte[] xBytes = stripLeadingZeroes(w.getAffineX().toByteArray());
if (xBytes.length > 32) {
throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected");
}
for (int n = 0; n < 32 - xBytes.length; n++) {
baos.write(0x00);
}
baos.write(xBytes);
byte[] yBytes = stripLeadingZeroes(w.getAffineY().toByteArray());
if (yBytes.length > 32) {
throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected");
}
for (int n = 0; n < 32 - yBytes.length; n++) {
baos.write(0x00);
}
baos.write(yBytes);
baos.write(new byte[]{43, 44});
} catch (IOException e) {
e.printStackTrace();