Skip to content

Commit

Permalink
Fix Deserialization error when "extensions" contains "extra" field (#10)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Nov 4, 2020
1 parent 8cd76b6 commit 027705c
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Intellij's dirty laundry
.idea/*
*.iml

#maven build artifcts
target/*
Expand Down
16 changes: 13 additions & 3 deletions src/io/calidog/certstream/CertStream.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.calidog.certstream;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -60,13 +61,13 @@ public static void onMessage(CertStreamMessageHandler handler)
CertStreamMessagePOJO msg;
try
{
msg = new Gson().fromJson(string, CertStreamMessagePOJO.class);
msg = certStreamGson.fromJson(string, CertStreamMessagePOJO.class);

if (msg.messageType.equalsIgnoreCase("heartbeat"))
{
return;
}
}catch (JsonSyntaxException e)
} catch (JsonSyntaxException e)
{
System.out.println(e.getMessage());
logger.warn("onMessage had an exception parsing some json", e);
Expand All @@ -87,6 +88,15 @@ public static void onMessage(CertStreamMessageHandler handler)
});
}

private static Gson certStreamGson =
new GsonBuilder()
.registerTypeAdapter
(
CertStreamCertificatePOJO.class,
new CertStreamCertificatePOJODeserializer()
)
.create();

/**
* @param handler A {@link Consumer<CertStreamMessage>} that we'll
* run in a Thread that stays alive as long
Expand All @@ -99,7 +109,7 @@ public static void onMessageAlternativeServer (CertStreamMessageHandler handler,
CertStreamMessagePOJO msg;

try {
msg = new Gson().fromJson(string, CertStreamMessagePOJO.class);
msg = certStreamGson.fromJson(string, CertStreamMessagePOJO.class);

if (msg.messageType.equalsIgnoreCase("heartbeat")) {
return;
Expand Down
53 changes: 25 additions & 28 deletions src/io/calidog/certstream/CertStreamCertificate.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package io.calidog.certstream;

import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.*;
import java.time.Instant;
import java.util.*;
Expand All @@ -16,7 +13,7 @@
*/
public class CertStreamCertificate extends X509Certificate {
private HashMap<String, String> subject;
private HashMap<String, String> extensions;
private HashMap<String, String[]> extensions;

private double notBefore;
private double notAfter;
Expand Down Expand Up @@ -77,25 +74,25 @@ public void checkValidity(Date date) throws CertificateExpiredException, Certifi
/**Not implemented*/
@Override
public int getVersion() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public BigInteger getSerialNumber() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public Principal getIssuerDN() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public X500Principal getIssuerX500Principal() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
Expand All @@ -122,66 +119,66 @@ public Date getNotAfter() {
/**Not implemented*/
@Override
public byte[] getTBSCertificate() throws CertificateEncodingException {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}
/**Not implemented*/
@Override
public byte[] getSignature() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public String getSigAlgName() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public String getSigAlgOID() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public byte[] getSigAlgParams() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public boolean[] getIssuerUniqueID() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public boolean[] getSubjectUniqueID() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public boolean[] getKeyUsage() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public List<String> getExtendedKeyUsage() throws CertificateParsingException {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public int getBasicConstraints() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

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

/**Not implemented*/
@Override
public void verify(PublicKey publicKey, String s) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public String toString() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public PublicKey getPublicKey() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public boolean hasUnsupportedCriticalExtension() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public Set<String> getCriticalExtensionOIDs() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public Set<String> getNonCriticalExtensionOIDs() {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**Not implemented*/
@Override
public byte[] getExtensionValue(String s) {
throw new NotImplementedException();
throw new UnsupportedOperationException();
}

/**
Expand All @@ -257,7 +254,7 @@ public byte[] getExtensionValue(String s) {
* passed-in oid String. The oid string is represented
* by whatever CertStream passes us.
*/
public String getStringExtensionValue(String key)
public String[] getStringExtensionValue(String key)
{
return extensions.get(key);
}
Expand Down
4 changes: 3 additions & 1 deletion src/io/calidog/certstream/CertStreamCertificatePOJO.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public class CertStreamCertificatePOJO {

HashMap<String, String> subject;

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

@SerializedName("not_before")
double notBefore;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.calidog.certstream;

import com.google.gson.*;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class CertStreamCertificatePOJODeserializer implements JsonDeserializer<CertStreamCertificatePOJO> {

@Override
public CertStreamCertificatePOJO deserialize(
JsonElement jsonElement,
Type type,
JsonDeserializationContext jsonDeserializationContext
) throws JsonParseException {

JsonObject jsonObj = jsonElement.getAsJsonObject();
JsonObject jsonExtensions = new JsonObject();

// remove extensions from json object
if (jsonObj.has("extensions"))
{
jsonExtensions = jsonObj.remove("extensions").getAsJsonObject();
}

// parse entry normally
CertStreamCertificatePOJO retVal = new Gson().fromJson(jsonElement, CertStreamCertificatePOJO.class);

// parse extensions externally
retVal.extensions = deserializeExtension(jsonExtensions);

return retVal;
}

private HashMap<String, String[]> deserializeExtension(JsonObject extensions){
final HashMap<String, String[]> finalMap = new HashMap<>(extensions.size());

extensions.entrySet().forEach((Map.Entry<String, JsonElement> entry) -> {
String key = entry.getKey();
JsonElement value = entry.getValue();
String[] extensionValues;

try {
extensionValues = new String[] { value.getAsString() };
} catch (IllegalStateException | UnsupportedOperationException e) {
JsonArray extensionJsonArray = value.getAsJsonArray();
extensionValues = new String[extensionJsonArray.size()];

for (int i = 0; i < extensionJsonArray.size(); i++) {
extensionValues[i] = extensionJsonArray.get(i).getAsString();
}
}

finalMap.put(key, extensionValues);
});

return finalMap;
}
}

0 comments on commit 027705c

Please sign in to comment.