Skip to content

Commit a22f388

Browse files
authored
Bugs/fix tpm parser (#31)
* Modify pubArea for ECC alg parsing error of TPM Attestation * Refactor TPM PubArea extraction code * Add unit test for TPM ECC attestation
1 parent 78f78c6 commit a22f388

File tree

3 files changed

+136
-58
lines changed

3 files changed

+136
-58
lines changed

server/src/main/java/com/linecorp/line/auth/fido/fido2/server/attestation/tpm/TpmKeyAlgorithm.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Arrays;
2020

21+
import com.linecorp.line.auth.fido.fido2.server.error.InternalErrorCode;
22+
import com.linecorp.line.auth.fido.fido2.server.exception.FIDO2ServerRuntimeException;
2123
import lombok.AllArgsConstructor;
2224
import lombok.Getter;
2325

@@ -32,6 +34,7 @@ public static TpmKeyAlgorithm fromValue(int value) {
3234
return Arrays.stream(TpmKeyAlgorithm.values())
3335
.filter(e -> e.value == value)
3436
.findFirst()
35-
.get();
37+
.orElseThrow(() -> new FIDO2ServerRuntimeException(InternalErrorCode.TPM_ATTESTATION_DATA_INVALID));
38+
3639
}
3740
}

server/src/main/java/com/linecorp/line/auth/fido/fido2/server/attestation/tpm/TpmParser.java

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
package com.linecorp.line.auth.fido.fido2.server.attestation.tpm;
1818

19+
import com.linecorp.line.auth.fido.fido2.server.error.InternalErrorCode;
20+
import com.linecorp.line.auth.fido.fido2.server.exception.FIDO2ServerRuntimeException;
21+
import com.linecorp.line.auth.fido.fido2.server.util.UnsignedUtil;
22+
1923
import java.io.ByteArrayInputStream;
2024
import java.io.IOException;
21-
22-
import com.linecorp.line.auth.fido.fido2.server.util.UnsignedUtil;
25+
import java.nio.ByteBuffer;
2326

2427
public class TpmParser {
2528
public static CertInfo parseCertInfo(byte[] certInfo) throws IOException {
@@ -89,27 +92,48 @@ public static CertInfo parseCertInfo(byte[] certInfo) throws IOException {
8992
}
9093

9194
public static PubArea parsePubArea(byte[] pubArea) throws IOException {
95+
ByteArrayInputStream pubAreaInputStream = new ByteArrayInputStream(pubArea);
96+
switch (TpmKeyAlgorithm.fromValue(extractTpmKeyAlgType(pubAreaInputStream))) {
97+
case RSA: {
98+
return createPubAreaForRSA(pubAreaInputStream);
99+
}
100+
case ECC: {
101+
return createPubAreaForECC(pubAreaInputStream);
102+
}
103+
}
104+
throw new FIDO2ServerRuntimeException(InternalErrorCode.TPM_ATTESTATION_DATA_INVALID);
105+
}
106+
107+
private static int extractTpmKeyAlgType(ByteArrayInputStream inputStream) throws IOException {
92108
byte[] typeBytes = new byte[2];
109+
inputStream.read(typeBytes);
110+
return UnsignedUtil.readUINT16BE(typeBytes);
111+
}
112+
113+
private static PubArea createPubAreaForRSA(ByteArrayInputStream inputStream) throws IOException {
114+
return createPubAreaBuilder(TpmKeyAlgorithm.RSA, inputStream)
115+
.parameters(extractParametersForRSA(inputStream))
116+
.unique(extractUniqueBytesForRSA(inputStream))
117+
.build();
118+
}
119+
120+
private static PubArea createPubAreaForECC(ByteArrayInputStream inputStream) throws IOException {
121+
return createPubAreaBuilder(TpmKeyAlgorithm.ECC, inputStream)
122+
.parameters(extractParametersForECC(inputStream))
123+
.unique(extractUniqueBytesForECC(inputStream))
124+
.build();
125+
}
126+
127+
private static PubArea.PubAreaBuilder createPubAreaBuilder(TpmKeyAlgorithm tpmKeyAlgType, ByteArrayInputStream inputStream) throws IOException {
93128
byte[] nameAlgBytes = new byte[2];
94129
byte[] objectAttributesBytes = new byte[4];
95130
byte[] authPolicyLengthBytes = new byte[2];
96-
byte[] symmetricBytes = new byte[2];
97-
byte[] schemeBytes = new byte[2];
98-
byte[] keyBitsBytes; // rsa key
99-
byte[] exponentBytes; // rsa key
100-
byte[] curveIdBytes; // ecc key
101-
byte[] kdfBytes; //ecc key
102-
byte[] uniqueLengthBytes = new byte[2];
103-
byte[] uniqueBytes;
104131

105-
ByteArrayInputStream inputStream = new ByteArrayInputStream(pubArea);
106-
107-
inputStream.read(typeBytes); // type
108-
int type = UnsignedUtil.readUINT16BE(typeBytes);
109-
inputStream.read(nameAlgBytes); // name alg
132+
inputStream.read(nameAlgBytes);
110133
TpmHashAlgorithm nameAlg =
111134
TpmHashAlgorithm.fromValue(UnsignedUtil.readUINT16BE(nameAlgBytes));
112-
inputStream.read(objectAttributesBytes); // object attributes
135+
136+
inputStream.read(objectAttributesBytes);
113137
int objectAttributesFlags = (int) UnsignedUtil.readUINT32BE(objectAttributesBytes);
114138
ObjectAttributes objectAttributes = parseObjectAttributes(objectAttributesFlags);
115139
// skip auth policy
@@ -119,50 +143,77 @@ public static PubArea parsePubArea(byte[] pubArea) throws IOException {
119143
inputStream.skip(authPolicyLength);
120144
}
121145

122-
// read parameters depending on the key type
123-
Parameters parameters = null;
124-
if (type == TpmKeyAlgorithm.RSA.getValue()) {
125-
keyBitsBytes = new byte[2];
126-
exponentBytes = new byte[4];
127-
inputStream.read(symmetricBytes);
128-
inputStream.read(schemeBytes);
129-
inputStream.read(keyBitsBytes);
130-
inputStream.read(exponentBytes);
131-
parameters = new RsaParameters();
132-
parameters.setSymmetric(symmetricBytes);
133-
parameters.setScheme(TpmSignatureAlgorithm.fromValue(UnsignedUtil.readUINT16BE(schemeBytes)));
134-
((RsaParameters) parameters).setKeyBits(keyBitsBytes);
135-
((RsaParameters) parameters).setExponent(exponentBytes);
136-
} else if (type == TpmKeyAlgorithm.ECC.getValue()) {
137-
curveIdBytes = new byte[2];
138-
kdfBytes = new byte[2];
139-
inputStream.read(symmetricBytes);
140-
inputStream.read(schemeBytes);
141-
inputStream.read(curveIdBytes);
142-
inputStream.read(kdfBytes);
143-
parameters = new EccParameters();
144-
parameters.setSymmetric(symmetricBytes);
145-
parameters.setScheme(TpmSignatureAlgorithm.fromValue(UnsignedUtil.readUINT16BE(schemeBytes)));
146-
((EccParameters) parameters).setCurveId(TpmEccCurve.fromValue(UnsignedUtil.readUINT16BE(curveIdBytes)));
147-
((EccParameters) parameters).setKdf(kdfBytes);
148-
} else {
149-
// invalid
150-
}
146+
return PubArea
147+
.builder()
148+
.type(tpmKeyAlgType)
149+
.nameAlg(nameAlg)
150+
.objectAttributes(objectAttributes);
151+
}
152+
153+
private static Parameters extractParametersForRSA(ByteArrayInputStream inputStream) throws IOException {
154+
byte[] symmetricBytes = new byte[2];
155+
byte[] schemeBytes = new byte[2];
156+
byte[] keyBitsBytes = new byte[2];
157+
byte[] exponentBytes = new byte[4];
158+
159+
inputStream.read(symmetricBytes);
160+
inputStream.read(schemeBytes);
161+
inputStream.read(keyBitsBytes);
162+
inputStream.read(exponentBytes);
151163

152-
// read unique (key value)
164+
Parameters parameters = new RsaParameters();
165+
parameters.setSymmetric(symmetricBytes);
166+
parameters.setScheme(TpmSignatureAlgorithm.fromValue(UnsignedUtil.readUINT16BE(schemeBytes)));
167+
((RsaParameters) parameters).setKeyBits(keyBitsBytes);
168+
((RsaParameters) parameters).setExponent(exponentBytes);
169+
return parameters;
170+
}
171+
172+
private static byte[] extractUniqueBytesForRSA(ByteArrayInputStream inputStream) throws IOException {
173+
byte[] uniqueLengthBytes = new byte[2];
153174
inputStream.read(uniqueLengthBytes);
154175
int uniqueLength = UnsignedUtil.readUINT16BE(uniqueLengthBytes);
155-
uniqueBytes = new byte[uniqueLength];
176+
byte[] uniqueBytes = new byte[uniqueLength];
156177
inputStream.read(uniqueBytes);
178+
return uniqueBytes;
179+
}
157180

158-
return PubArea
159-
.builder()
160-
.type(TpmKeyAlgorithm.fromValue(type))
161-
.nameAlg(nameAlg)
162-
.objectAttributes(objectAttributes)
163-
.parameters(parameters)
164-
.unique(uniqueBytes)
165-
.build();
181+
private static Parameters extractParametersForECC(ByteArrayInputStream inputStream) throws IOException {
182+
byte[] symmetricBytes = new byte[2];
183+
byte[] schemeBytes = new byte[2];
184+
byte[] curveIdBytes = new byte[2];
185+
byte[] kdfBytes = new byte[2];
186+
187+
inputStream.read(symmetricBytes);
188+
inputStream.read(schemeBytes);
189+
inputStream.read(curveIdBytes);
190+
inputStream.read(kdfBytes);
191+
192+
Parameters parameters = new EccParameters();
193+
parameters.setSymmetric(symmetricBytes);
194+
parameters.setScheme(TpmSignatureAlgorithm.fromValue(UnsignedUtil.readUINT16BE(schemeBytes)));
195+
((EccParameters) parameters).setCurveId(TpmEccCurve.fromValue(UnsignedUtil.readUINT16BE(curveIdBytes)));
196+
((EccParameters) parameters).setKdf(kdfBytes);
197+
return parameters;
198+
}
199+
200+
private static byte[] extractUniqueBytesForECC(ByteArrayInputStream inputStream) throws IOException {
201+
byte[] xLengthBytes = new byte[2];
202+
inputStream.read(xLengthBytes);
203+
int xLength = UnsignedUtil.readUINT16BE(xLengthBytes);
204+
byte[] xBytes = new byte[xLength];
205+
inputStream.read(xBytes);
206+
207+
byte[] yLengthBytes = new byte[2];
208+
inputStream.read(yLengthBytes);
209+
int yLength = UnsignedUtil.readUINT16BE(yLengthBytes);
210+
byte[] yBytes = new byte[yLength];
211+
inputStream.read(yBytes);
212+
213+
return ByteBuffer.allocate(xLength + yLength)
214+
.put(xBytes)
215+
.put(yBytes)
216+
.array();
166217
}
167218

168219
public static ClockInfo parseClockInfo(byte[] clockInfo) throws IOException {

0 commit comments

Comments
 (0)