From 658edd901def7b997a26c456ff23373788133c81 Mon Sep 17 00:00:00 2001 From: Joshua Hight Date: Fri, 17 Apr 2020 16:58:47 -0700 Subject: [PATCH 1/3] use custom deserialization to handle list extensions --- src/io/calidog/certstream/CertStream.java | 16 ++++- .../certstream/CertStreamCertificate.java | 4 +- .../certstream/CertStreamCertificatePOJO.java | 4 +- ...CertStreamCertificatePOJODeserializer.java | 62 +++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java diff --git a/src/io/calidog/certstream/CertStream.java b/src/io/calidog/certstream/CertStream.java index 0144cfa..5664c0e 100644 --- a/src/io/calidog/certstream/CertStream.java +++ b/src/io/calidog/certstream/CertStream.java @@ -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; @@ -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); @@ -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} that we'll * run in a Thread that stays alive as long @@ -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; diff --git a/src/io/calidog/certstream/CertStreamCertificate.java b/src/io/calidog/certstream/CertStreamCertificate.java index e9956ef..710f54f 100644 --- a/src/io/calidog/certstream/CertStreamCertificate.java +++ b/src/io/calidog/certstream/CertStreamCertificate.java @@ -16,7 +16,7 @@ */ public class CertStreamCertificate extends X509Certificate { private HashMap subject; - private HashMap extensions; + private HashMap extensions; private double notBefore; private double notAfter; @@ -257,7 +257,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); } diff --git a/src/io/calidog/certstream/CertStreamCertificatePOJO.java b/src/io/calidog/certstream/CertStreamCertificatePOJO.java index 8b2f5a3..a4717a8 100644 --- a/src/io/calidog/certstream/CertStreamCertificatePOJO.java +++ b/src/io/calidog/certstream/CertStreamCertificatePOJO.java @@ -12,7 +12,9 @@ public class CertStreamCertificatePOJO { HashMap subject; - HashMap extensions; + // values can be either strings or lists of strings, so we use a a custom deserializer + // that converts strings into singleton arrays + HashMap extensions; @SerializedName("not_before") double notBefore; diff --git a/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java b/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java new file mode 100644 index 0000000..0be5f5e --- /dev/null +++ b/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java @@ -0,0 +1,62 @@ +package io.calidog.certstream; + +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.util.HashMap; + +public class CertStreamCertificatePOJODeserializer implements JsonDeserializer { + + @Override + public CertStreamCertificatePOJO deserialize( + JsonElement jsonElement, + Type type, + JsonDeserializationContext jsonDeserializationContext + ) throws JsonParseException { + JsonObject jsonObj = jsonElement.getAsJsonObject(); + + JsonObject jsonExtensions; + + HashMap extensionMap = null; + + if (jsonObj.has("extensions")) + { + jsonExtensions = jsonObj.remove("extensions").getAsJsonObject(); + + final HashMap finalExtensionMap = new HashMap<>(jsonExtensions.size()); + + jsonExtensions + .entrySet() + .forEach + ( + (java.util.Map.Entry entry) -> + { + String key = entry.getKey(); + JsonElement value = entry.getValue(); + String[] extensionValueList; + try { + extensionValueList = new String[] { value.getAsString() }; + } catch (IllegalStateException | UnsupportedOperationException e) { + JsonArray extensionJsonArray = value.getAsJsonArray(); + extensionValueList = new String[extensionJsonArray.size()]; + + for (int i = 0; i < extensionJsonArray.size(); i++) { + extensionValueList[i] = extensionJsonArray.get(i).getAsString(); + } + } + + finalExtensionMap.put(key, extensionValueList); + } + ); + + extensionMap = finalExtensionMap; + } + + CertStreamCertificatePOJO retVal = + jsonDeserializationContext.deserialize(jsonElement, type); + + retVal.extensions = extensionMap; + + return retVal; + } +} From 73a0a124ea5dc2114f81491cafb3c414627b6674 Mon Sep 17 00:00:00 2001 From: nitram22 Date: Thu, 9 Jul 2020 14:22:31 +0200 Subject: [PATCH 2/3] Fix parsing error when extensions contain "extra" field --- .gitignore | 1 + .../certstream/CertStreamCertificate.java | 49 +++++++------ ...CertStreamCertificatePOJODeserializer.java | 68 +++++++++---------- 3 files changed, 57 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 41e5e31..3814eff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ #Intellij's dirty laundry .idea/* +*.iml #maven build artifcts target/* diff --git a/src/io/calidog/certstream/CertStreamCertificate.java b/src/io/calidog/certstream/CertStreamCertificate.java index 710f54f..57437c5 100644 --- a/src/io/calidog/certstream/CertStreamCertificate.java +++ b/src/io/calidog/certstream/CertStreamCertificate.java @@ -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.*; @@ -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*/ @@ -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 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> getSubjectAlternativeNames() throws CertificateParsingException { - throw new NotImplementedException(); + throw new UnsupportedOperationException(); } @Override @@ -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 getCriticalExtensionOIDs() { - throw new NotImplementedException(); + throw new UnsupportedOperationException(); } /**Not implemented*/ @Override public Set getNonCriticalExtensionOIDs() { - throw new NotImplementedException(); + throw new UnsupportedOperationException(); } /**Not implemented*/ @Override public byte[] getExtensionValue(String s) { - throw new NotImplementedException(); + throw new UnsupportedOperationException(); } /** diff --git a/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java b/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java index 0be5f5e..787d29c 100644 --- a/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java +++ b/src/io/calidog/certstream/CertStreamCertificatePOJODeserializer.java @@ -4,6 +4,7 @@ import java.lang.reflect.Type; import java.util.HashMap; +import java.util.Map; public class CertStreamCertificatePOJODeserializer implements JsonDeserializer { @@ -13,50 +14,47 @@ public CertStreamCertificatePOJO deserialize( Type type, JsonDeserializationContext jsonDeserializationContext ) throws JsonParseException { - JsonObject jsonObj = jsonElement.getAsJsonObject(); - - JsonObject jsonExtensions; - HashMap extensionMap = null; + JsonObject jsonObj = jsonElement.getAsJsonObject(); + JsonObject jsonExtensions = new JsonObject(); + // remove extensions from json object if (jsonObj.has("extensions")) { jsonExtensions = jsonObj.remove("extensions").getAsJsonObject(); - - final HashMap finalExtensionMap = new HashMap<>(jsonExtensions.size()); - - jsonExtensions - .entrySet() - .forEach - ( - (java.util.Map.Entry entry) -> - { - String key = entry.getKey(); - JsonElement value = entry.getValue(); - String[] extensionValueList; - try { - extensionValueList = new String[] { value.getAsString() }; - } catch (IllegalStateException | UnsupportedOperationException e) { - JsonArray extensionJsonArray = value.getAsJsonArray(); - extensionValueList = new String[extensionJsonArray.size()]; - - for (int i = 0; i < extensionJsonArray.size(); i++) { - extensionValueList[i] = extensionJsonArray.get(i).getAsString(); - } - } - - finalExtensionMap.put(key, extensionValueList); - } - ); - - extensionMap = finalExtensionMap; } - CertStreamCertificatePOJO retVal = - jsonDeserializationContext.deserialize(jsonElement, type); + // parse entry normally + CertStreamCertificatePOJO retVal = new Gson().fromJson(jsonElement, CertStreamCertificatePOJO.class); - retVal.extensions = extensionMap; + // parse extensions externally + retVal.extensions = deserializeExtension(jsonExtensions); return retVal; } + + private HashMap deserializeExtension(JsonObject extensions){ + final HashMap finalMap = new HashMap<>(extensions.size()); + + extensions.entrySet().forEach((Map.Entry 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; + } } From b04b7de906d2cf2b90ee42890d485a3d153ec5f3 Mon Sep 17 00:00:00 2001 From: Martin Wilhelm Date: Fri, 9 Jul 2021 20:56:24 +0200 Subject: [PATCH 3/3] Fix data structure causing nullpointer --- .../certstream/CertStreamCertificate.java | 19 +++++++------------ .../certstream/CertStreamCertificatePOJO.java | 6 ++++-- .../certstream/CertStreamMessageData.java | 11 +++-------- .../certstream/CertStreamMessageDataPOJO.java | 5 +++-- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/io/calidog/certstream/CertStreamCertificate.java b/src/io/calidog/certstream/CertStreamCertificate.java index 57437c5..ac77d07 100644 --- a/src/io/calidog/certstream/CertStreamCertificate.java +++ b/src/io/calidog/certstream/CertStreamCertificate.java @@ -14,11 +14,12 @@ public class CertStreamCertificate extends X509Certificate { private HashMap subject; private HashMap extensions; + private HashMap issuer; private double notBefore; private double notAfter; - private String asDer; + String sigAlg; String serialNumber; @@ -31,12 +32,9 @@ private CertStreamCertificate() {} public static CertStreamCertificate fromPOJO(CertStreamCertificatePOJO pojo) throws CertificateException { CertStreamCertificate fullCertificate = new CertStreamCertificate(); - if (pojo.asDer.isEmpty()) - { - return null; - } + fullCertificate.issuer = pojo.issuer; - fullCertificate.asDer = pojo.asDer; + fullCertificate.sigAlg = pojo.sigAlg; fullCertificate.extensions = pojo.extensions; @@ -191,13 +189,10 @@ public void verify(PublicKey publicKey, Provider provider) throws CertificateExc super.verify(publicKey, provider); } - private byte[] memoizedEncodedCert = null; @Override - public byte[] getEncoded() throws CertificateEncodingException { - if (memoizedEncodedCert == null) { - memoizedEncodedCert = Base64.getDecoder().decode(asDer); - } - return Arrays.copyOf(memoizedEncodedCert, memoizedEncodedCert.length); + public byte[] getEncoded() { + + return new byte[1]; } /**Not implemented*/ diff --git a/src/io/calidog/certstream/CertStreamCertificatePOJO.java b/src/io/calidog/certstream/CertStreamCertificatePOJO.java index a4717a8..15dd11c 100644 --- a/src/io/calidog/certstream/CertStreamCertificatePOJO.java +++ b/src/io/calidog/certstream/CertStreamCertificatePOJO.java @@ -12,6 +12,8 @@ public class CertStreamCertificatePOJO { HashMap subject; + HashMap issuer; + // values can be either strings or lists of strings, so we use a a custom deserializer // that converts strings into singleton arrays HashMap extensions; @@ -22,8 +24,8 @@ public class CertStreamCertificatePOJO { @SerializedName("not_after") double notAfter; - @SerializedName("as_der") - String asDer; + @SerializedName("signature_algorithm") + String sigAlg; @SerializedName("serial_number") String serialNumber; diff --git a/src/io/calidog/certstream/CertStreamMessageData.java b/src/io/calidog/certstream/CertStreamMessageData.java index a0ebfae..72e88b2 100644 --- a/src/io/calidog/certstream/CertStreamMessageData.java +++ b/src/io/calidog/certstream/CertStreamMessageData.java @@ -11,9 +11,9 @@ public class CertStreamMessageData { String updateType; - CertStreamCertificate leafCert; + String certLink; - CertStreamCertificate[] chain; + CertStreamCertificate leafCert; long certIndex; @@ -36,12 +36,7 @@ public static CertStreamMessageData fromPOJO(CertStreamMessageDataPOJO pojo) thr fullData.leafCert = CertStreamCertificate.fromPOJO(pojo.leafCert); - fullData.chain = new CertStreamCertificate[pojo.chain.length]; - - for (int i = 0; i < fullData.chain.length; i++) - { - fullData.chain[i] = CertStreamCertificate.fromPOJO(pojo.chain[i]); - } + fullData.certLink = pojo.certLink; fullData.source = pojo.source; diff --git a/src/io/calidog/certstream/CertStreamMessageDataPOJO.java b/src/io/calidog/certstream/CertStreamMessageDataPOJO.java index f17628c..99399f9 100644 --- a/src/io/calidog/certstream/CertStreamMessageDataPOJO.java +++ b/src/io/calidog/certstream/CertStreamMessageDataPOJO.java @@ -6,11 +6,12 @@ public class CertStreamMessageDataPOJO { @SerializedName("update_type") String updateType; + @SerializedName("cert_link") + String certLink; + @SerializedName("leaf_cert") CertStreamCertificatePOJO leafCert; - CertStreamCertificatePOJO[] chain; - @SerializedName("cert_index") long certIndex;