Skip to content

Commit 027705c

Browse files
nitram22joshbooksMartin Wilhelm
authored
Fix Deserialization error when "extensions" contains "extra" field (#10)
* use custom deserialization to handle list extensions * Fix parsing error when extensions contain "extra" field Co-authored-by: Joshua Hight <[email protected]> Co-authored-by: Martin Wilhelm <[email protected]>
1 parent 8cd76b6 commit 027705c

5 files changed

+102
-32
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#Intellij's dirty laundry
22
.idea/*
3+
*.iml
34

45
#maven build artifcts
56
target/*

src/io/calidog/certstream/CertStream.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.calidog.certstream;
22

33
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
45
import com.google.gson.JsonSyntaxException;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
@@ -60,13 +61,13 @@ public static void onMessage(CertStreamMessageHandler handler)
6061
CertStreamMessagePOJO msg;
6162
try
6263
{
63-
msg = new Gson().fromJson(string, CertStreamMessagePOJO.class);
64+
msg = certStreamGson.fromJson(string, CertStreamMessagePOJO.class);
6465

6566
if (msg.messageType.equalsIgnoreCase("heartbeat"))
6667
{
6768
return;
6869
}
69-
}catch (JsonSyntaxException e)
70+
} catch (JsonSyntaxException e)
7071
{
7172
System.out.println(e.getMessage());
7273
logger.warn("onMessage had an exception parsing some json", e);
@@ -87,6 +88,15 @@ public static void onMessage(CertStreamMessageHandler handler)
8788
});
8889
}
8990

91+
private static Gson certStreamGson =
92+
new GsonBuilder()
93+
.registerTypeAdapter
94+
(
95+
CertStreamCertificatePOJO.class,
96+
new CertStreamCertificatePOJODeserializer()
97+
)
98+
.create();
99+
90100
/**
91101
* @param handler A {@link Consumer<CertStreamMessage>} that we'll
92102
* run in a Thread that stays alive as long
@@ -99,7 +109,7 @@ public static void onMessageAlternativeServer (CertStreamMessageHandler handler,
99109
CertStreamMessagePOJO msg;
100110

101111
try {
102-
msg = new Gson().fromJson(string, CertStreamMessagePOJO.class);
112+
msg = certStreamGson.fromJson(string, CertStreamMessagePOJO.class);
103113

104114
if (msg.messageType.equalsIgnoreCase("heartbeat")) {
105115
return;

src/io/calidog/certstream/CertStreamCertificate.java

+25-28
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package io.calidog.certstream;
22

3-
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
4-
53
import javax.security.auth.x500.X500Principal;
64
import java.math.BigInteger;
75
import java.security.*;
8-
import java.security.cert.Certificate;
96
import java.security.cert.*;
107
import java.time.Instant;
118
import java.util.*;
@@ -16,7 +13,7 @@
1613
*/
1714
public class CertStreamCertificate extends X509Certificate {
1815
private HashMap<String, String> subject;
19-
private HashMap<String, String> extensions;
16+
private HashMap<String, String[]> extensions;
2017

2118
private double notBefore;
2219
private double notAfter;
@@ -77,25 +74,25 @@ public void checkValidity(Date date) throws CertificateExpiredException, Certifi
7774
/**Not implemented*/
7875
@Override
7976
public int getVersion() {
80-
throw new NotImplementedException();
77+
throw new UnsupportedOperationException();
8178
}
8279

8380
/**Not implemented*/
8481
@Override
8582
public BigInteger getSerialNumber() {
86-
throw new NotImplementedException();
83+
throw new UnsupportedOperationException();
8784
}
8885

8986
/**Not implemented*/
9087
@Override
9188
public Principal getIssuerDN() {
92-
throw new NotImplementedException();
89+
throw new UnsupportedOperationException();
9390
}
9491

9592
/**Not implemented*/
9693
@Override
9794
public X500Principal getIssuerX500Principal() {
98-
throw new NotImplementedException();
95+
throw new UnsupportedOperationException();
9996
}
10097

10198
/**Not implemented*/
@@ -122,66 +119,66 @@ public Date getNotAfter() {
122119
/**Not implemented*/
123120
@Override
124121
public byte[] getTBSCertificate() throws CertificateEncodingException {
125-
throw new NotImplementedException();
122+
throw new UnsupportedOperationException();
126123
}
127124
/**Not implemented*/
128125
@Override
129126
public byte[] getSignature() {
130-
throw new NotImplementedException();
127+
throw new UnsupportedOperationException();
131128
}
132129

133130
/**Not implemented*/
134131
@Override
135132
public String getSigAlgName() {
136-
throw new NotImplementedException();
133+
throw new UnsupportedOperationException();
137134
}
138135

139136
/**Not implemented*/
140137
@Override
141138
public String getSigAlgOID() {
142-
throw new NotImplementedException();
139+
throw new UnsupportedOperationException();
143140
}
144141

145142
/**Not implemented*/
146143
@Override
147144
public byte[] getSigAlgParams() {
148-
throw new NotImplementedException();
145+
throw new UnsupportedOperationException();
149146
}
150147

151148
/**Not implemented*/
152149
@Override
153150
public boolean[] getIssuerUniqueID() {
154-
throw new NotImplementedException();
151+
throw new UnsupportedOperationException();
155152
}
156153

157154
/**Not implemented*/
158155
@Override
159156
public boolean[] getSubjectUniqueID() {
160-
throw new NotImplementedException();
157+
throw new UnsupportedOperationException();
161158
}
162159

163160
/**Not implemented*/
164161
@Override
165162
public boolean[] getKeyUsage() {
166-
throw new NotImplementedException();
163+
throw new UnsupportedOperationException();
167164
}
168165

169166
/**Not implemented*/
170167
@Override
171168
public List<String> getExtendedKeyUsage() throws CertificateParsingException {
172-
throw new NotImplementedException();
169+
throw new UnsupportedOperationException();
173170
}
174171

175172
/**Not implemented*/
176173
@Override
177174
public int getBasicConstraints() {
178-
throw new NotImplementedException();
175+
throw new UnsupportedOperationException();
179176
}
180177

181178
/**Not implemented*/
182179
@Override
183180
public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
184-
throw new NotImplementedException();
181+
throw new UnsupportedOperationException();
185182
}
186183

187184
@Override
@@ -206,49 +203,49 @@ public byte[] getEncoded() throws CertificateEncodingException {
206203
/**Not implemented*/
207204
@Override
208205
public void verify(PublicKey publicKey) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
209-
throw new NotImplementedException();
206+
throw new UnsupportedOperationException();
210207
}
211208

212209
/**Not implemented*/
213210
@Override
214211
public void verify(PublicKey publicKey, String s) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
215-
throw new NotImplementedException();
212+
throw new UnsupportedOperationException();
216213
}
217214

218215
/**Not implemented*/
219216
@Override
220217
public String toString() {
221-
throw new NotImplementedException();
218+
throw new UnsupportedOperationException();
222219
}
223220

224221
/**Not implemented*/
225222
@Override
226223
public PublicKey getPublicKey() {
227-
throw new NotImplementedException();
224+
throw new UnsupportedOperationException();
228225
}
229226

230227
/**Not implemented*/
231228
@Override
232229
public boolean hasUnsupportedCriticalExtension() {
233-
throw new NotImplementedException();
230+
throw new UnsupportedOperationException();
234231
}
235232

236233
/**Not implemented*/
237234
@Override
238235
public Set<String> getCriticalExtensionOIDs() {
239-
throw new NotImplementedException();
236+
throw new UnsupportedOperationException();
240237
}
241238

242239
/**Not implemented*/
243240
@Override
244241
public Set<String> getNonCriticalExtensionOIDs() {
245-
throw new NotImplementedException();
242+
throw new UnsupportedOperationException();
246243
}
247244

248245
/**Not implemented*/
249246
@Override
250247
public byte[] getExtensionValue(String s) {
251-
throw new NotImplementedException();
248+
throw new UnsupportedOperationException();
252249
}
253250

254251
/**
@@ -257,7 +254,7 @@ public byte[] getExtensionValue(String s) {
257254
* passed-in oid String. The oid string is represented
258255
* by whatever CertStream passes us.
259256
*/
260-
public String getStringExtensionValue(String key)
257+
public String[] getStringExtensionValue(String key)
261258
{
262259
return extensions.get(key);
263260
}

src/io/calidog/certstream/CertStreamCertificatePOJO.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public class CertStreamCertificatePOJO {
1212

1313
HashMap<String, String> subject;
1414

15-
HashMap<String, String> extensions;
15+
// values can be either strings or lists of strings, so we use a a custom deserializer
16+
// that converts strings into singleton arrays
17+
HashMap<String, String[]> extensions;
1618

1719
@SerializedName("not_before")
1820
double notBefore;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package io.calidog.certstream;
2+
3+
import com.google.gson.*;
4+
5+
import java.lang.reflect.Type;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
public class CertStreamCertificatePOJODeserializer implements JsonDeserializer<CertStreamCertificatePOJO> {
10+
11+
@Override
12+
public CertStreamCertificatePOJO deserialize(
13+
JsonElement jsonElement,
14+
Type type,
15+
JsonDeserializationContext jsonDeserializationContext
16+
) throws JsonParseException {
17+
18+
JsonObject jsonObj = jsonElement.getAsJsonObject();
19+
JsonObject jsonExtensions = new JsonObject();
20+
21+
// remove extensions from json object
22+
if (jsonObj.has("extensions"))
23+
{
24+
jsonExtensions = jsonObj.remove("extensions").getAsJsonObject();
25+
}
26+
27+
// parse entry normally
28+
CertStreamCertificatePOJO retVal = new Gson().fromJson(jsonElement, CertStreamCertificatePOJO.class);
29+
30+
// parse extensions externally
31+
retVal.extensions = deserializeExtension(jsonExtensions);
32+
33+
return retVal;
34+
}
35+
36+
private HashMap<String, String[]> deserializeExtension(JsonObject extensions){
37+
final HashMap<String, String[]> finalMap = new HashMap<>(extensions.size());
38+
39+
extensions.entrySet().forEach((Map.Entry<String, JsonElement> entry) -> {
40+
String key = entry.getKey();
41+
JsonElement value = entry.getValue();
42+
String[] extensionValues;
43+
44+
try {
45+
extensionValues = new String[] { value.getAsString() };
46+
} catch (IllegalStateException | UnsupportedOperationException e) {
47+
JsonArray extensionJsonArray = value.getAsJsonArray();
48+
extensionValues = new String[extensionJsonArray.size()];
49+
50+
for (int i = 0; i < extensionJsonArray.size(); i++) {
51+
extensionValues[i] = extensionJsonArray.get(i).getAsString();
52+
}
53+
}
54+
55+
finalMap.put(key, extensionValues);
56+
});
57+
58+
return finalMap;
59+
}
60+
}

0 commit comments

Comments
 (0)