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:
parent
af43ae73f9
commit
e678b870a2
2 changed files with 62 additions and 14 deletions
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue