Skip to content

Commit 7d8b7bc

Browse files
committed
Adapt TlsUtils to Java 6
[#163862785] References #441
1 parent 8961964 commit 7d8b7bc

File tree

1 file changed

+103
-39
lines changed

1 file changed

+103
-39
lines changed

src/main/java/com/rabbitmq/client/impl/TlsUtils.java

Lines changed: 103 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@
2323
import java.security.cert.CertificateParsingException;
2424
import java.security.cert.X509Certificate;
2525
import java.util.*;
26-
import java.util.function.BiFunction;
27-
import java.util.stream.Collectors;
2826

2927
/**
3028
* Utility to extract information from X509 certificates.
3129
*
32-
* @since 5.7.0
30+
* @since 4.11.0
3331
*/
3432
public class TlsUtils {
3533

@@ -47,25 +45,53 @@ public class TlsUtils {
4745
put("1.3.6.1.5.5.7.3.8", "Binding the hash of an object to a time from an agreed-upon time");
4846
}});
4947
private static String PARSING_ERROR = "<parsing-error>";
50-
private static final Map<String, BiFunction<byte[], X509Certificate, String>> EXTENSIONS = Collections.unmodifiableMap(
51-
new HashMap<String, BiFunction<byte[], X509Certificate, String>>() {{
52-
put("2.5.29.14", (v, c) -> "SubjectKeyIdentifier = " + octetStringHexDump(v));
53-
put("2.5.29.15", (v, c) -> "KeyUsage = " + keyUsageBitString(c.getKeyUsage(), v));
54-
put("2.5.29.16", (v, c) -> "PrivateKeyUsage = " + hexDump(0, v));
55-
put("2.5.29.17", (v, c) -> {
56-
try {
57-
return "SubjectAlternativeName = " + sans(c, "/");
58-
} catch (CertificateParsingException e) {
59-
return "SubjectAlternativeName = " + PARSING_ERROR;
48+
private static final Map<String, ExtensionStringConverter> EXTENSIONS = Collections.unmodifiableMap(
49+
new HashMap<String, ExtensionStringConverter>() {{
50+
put("2.5.29.14", new ExtensionStringConverter() {
51+
@Override
52+
public String convert(byte[] derOctetString, X509Certificate certificate) {
53+
return "SubjectKeyIdentifier = " + octetStringHexDump(derOctetString);
54+
}
55+
});
56+
put("2.5.29.15", new ExtensionStringConverter() {
57+
@Override
58+
public String convert(byte[] derOctetString, X509Certificate certificate) {
59+
return "KeyUsage = " + keyUsageBitString(certificate.getKeyUsage(), derOctetString);
60+
}
61+
});
62+
put("2.5.29.16", new HexDumpConverter("PrivateKeyUsage"));
63+
put("2.5.29.17", new ExtensionStringConverter() {
64+
@Override
65+
public String convert(byte[] derOctetString, X509Certificate certificate) {
66+
try {
67+
return "SubjectAlternativeName = " + sans(certificate, "/");
68+
} catch (CertificateParsingException e) {
69+
return "SubjectAlternativeName = " + PARSING_ERROR;
70+
}
71+
}
72+
});
73+
put("2.5.29.18", new HexDumpConverter("IssuerAlternativeName"));
74+
put("2.5.29.19", new ExtensionStringConverter() {
75+
@Override
76+
public String convert(byte[] derOctetString, X509Certificate certificate) {
77+
return "BasicConstraints = " + basicConstraints(derOctetString);
78+
}
79+
});
80+
put("2.5.29.30", new HexDumpConverter("NameConstraints"));
81+
put("2.5.29.33", new HexDumpConverter("PolicyMappings"));
82+
put("2.5.29.35", new ExtensionStringConverter() {
83+
@Override
84+
public String convert(byte[] derOctetString, X509Certificate certificate) {
85+
return "AuthorityKeyIdentifier = " + authorityKeyIdentifier(derOctetString);
86+
}
87+
});
88+
put("2.5.29.36", new HexDumpConverter("PolicyConstraints"));
89+
put("2.5.29.37", new ExtensionStringConverter() {
90+
@Override
91+
public String convert(byte[] derOctetString, X509Certificate certificate) {
92+
return "ExtendedKeyUsage = " + extendedKeyUsage(derOctetString, certificate);
6093
}
6194
});
62-
put("2.5.29.18", (v, c) -> "IssuerAlternativeName = " + hexDump(0, v));
63-
put("2.5.29.19", (v, c) -> "BasicConstraints = " + basicConstraints(v));
64-
put("2.5.29.30", (v, c) -> "NameConstraints = " + hexDump(0, v));
65-
put("2.5.29.33", (v, c) -> "PolicyMappings = " + hexDump(0, v));
66-
put("2.5.29.35", (v, c) -> "AuthorityKeyIdentifier = " + authorityKeyIdentifier(v));
67-
put("2.5.29.36", (v, c) -> "PolicyConstraints = " + hexDump(0, v));
68-
put("2.5.29.37", (v, c) -> "ExtendedKeyUsage = " + extendedKeyUsage(v, c));
6995
}});
7096

7197
/**
@@ -96,7 +122,7 @@ public static void logPeerCertificateInfo(SSLSession session) {
96122
* Get a string representation of certificate info.
97123
*
98124
* @param certificate the certificate to analyze
99-
* @param prefix the line prefix
125+
* @param prefix the line prefix
100126
* @return information about the certificate
101127
*/
102128
public static String peerCertificateInfo(Certificate certificate, String prefix) {
@@ -112,13 +138,12 @@ public static String peerCertificateInfo(Certificate certificate, String prefix)
112138
}
113139

114140
private static String sans(X509Certificate c, String separator) throws CertificateParsingException {
115-
return String.join(separator, Optional.ofNullable(c.getSubjectAlternativeNames())
116-
.orElse(new ArrayList<>())
117-
.stream()
118-
.map(v -> v.toString())
119-
.collect(Collectors.toList()));
141+
Collection<List<?>> sans = c.getSubjectAlternativeNames();
142+
sans = sans == null ? new ArrayList<List<?>>() : sans;
143+
return join(separator, new ArrayList<List<?>>(sans));
120144
}
121145

146+
122147
/**
123148
* Human-readable representation of an X509 certificate extension.
124149
* <p>
@@ -129,31 +154,34 @@ private static String sans(X509Certificate c, String separator) throws Certifica
129154
* other DER-encoded objects, making a comprehensive support in this utility
130155
* impossible.
131156
*
132-
* @param oid extension OID
157+
* @param oid extension OID
133158
* @param derOctetString the extension value as a DER octet string
134-
* @param certificate the certificate
159+
* @param certificate the certificate
135160
* @return the OID and the value
136161
* @see <a href="http://luca.ntop.org/Teaching/Appunti/asn1.html">A Layman's Guide to a Subset of ASN.1, BER, and DER</a>
137162
* @see <a href="https://docs.microsoft.com/en-us/windows/desktop/seccertenroll/about-der-encoding-of-asn-1-types">DER Encoding of ASN.1 Types</a>
138163
*/
139164
public static String extensionPrettyPrint(String oid, byte[] derOctetString, X509Certificate certificate) {
140165
try {
141-
return EXTENSIONS.getOrDefault(oid, (v, c) -> oid + " = " + hexDump(0, derOctetString))
142-
.apply(derOctetString, certificate);
166+
ExtensionStringConverter converter = EXTENSIONS.get(oid);
167+
if (converter == null) {
168+
converter = new HexDumpConverter(oid);
169+
}
170+
return converter.convert(derOctetString, certificate);
143171
} catch (Exception e) {
144172
return oid + " = " + PARSING_ERROR;
145173
}
146174
}
147175

148176
private static String extensions(X509Certificate certificate) {
149-
List<String> extensions = new ArrayList<>();
177+
List<String> extensions = new ArrayList<String>();
150178
for (String oid : certificate.getCriticalExtensionOIDs()) {
151179
extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (critical)");
152180
}
153181
for (String oid : certificate.getNonCriticalExtensionOIDs()) {
154182
extensions.add(extensionPrettyPrint(oid, certificate.getExtensionValue(oid), certificate) + " (non-critical)");
155183
}
156-
return String.join(", ", extensions);
184+
return join(", ", extensions);
157185
}
158186

159187
private static String octetStringHexDump(byte[] derOctetString) {
@@ -166,22 +194,22 @@ private static String octetStringHexDump(byte[] derOctetString) {
166194
}
167195

168196
private static String hexDump(int start, byte[] derOctetString) {
169-
List<String> hexs = new ArrayList<>();
197+
List<String> hexs = new ArrayList<String>();
170198
for (int i = start; i < derOctetString.length; i++) {
171199
hexs.add(String.format("%02X", derOctetString[i]));
172200
}
173-
return String.join(":", hexs);
201+
return join(":", hexs);
174202
}
175203

176204
private static String keyUsageBitString(boolean[] keyUsage, byte[] derOctetString) {
177205
if (keyUsage != null) {
178-
List<String> usage = new ArrayList<>();
206+
List<String> usage = new ArrayList<String>();
179207
for (int i = 0; i < keyUsage.length; i++) {
180208
if (keyUsage[i]) {
181209
usage.add(KEY_USAGE.get(i));
182210
}
183211
}
184-
return String.join("/", usage);
212+
return join("/", usage);
185213
} else {
186214
return hexDump(0, derOctetString);
187215
}
@@ -217,13 +245,49 @@ private static String extendedKeyUsage(byte[] derOctetString, X509Certificate ce
217245
if (extendedKeyUsage == null) {
218246
return hexDump(0, derOctetString);
219247
} else {
220-
return String.join("/", extendedKeyUsage.stream()
221-
.map(oid -> EXTENDED_KEY_USAGE.getOrDefault(oid, oid))
222-
.collect(Collectors.toList()));
248+
List<String> extendedKeyUsageLiteral = new ArrayList<String>();
249+
for (String oid : extendedKeyUsage) {
250+
String literal = EXTENDED_KEY_USAGE.get(oid);
251+
extendedKeyUsageLiteral.add(literal == null ? oid : literal);
252+
}
253+
return join("/", extendedKeyUsageLiteral);
223254
}
224255
} catch (CertificateParsingException e) {
225256
return PARSING_ERROR;
226257
}
227258
}
228259

260+
private static String join(String separator, List<?> items) {
261+
StringBuilder builder = new StringBuilder();
262+
if (items != null) {
263+
for (int i = 0; i < items.size(); i++) {
264+
if (i > 0) {
265+
builder.append(separator);
266+
}
267+
builder.append(items.get(i));
268+
}
269+
}
270+
return builder.toString();
271+
}
272+
273+
private interface ExtensionStringConverter {
274+
275+
String convert(byte[] derOctetString, X509Certificate certificate);
276+
277+
}
278+
279+
private static class HexDumpConverter implements ExtensionStringConverter {
280+
281+
private final String extension;
282+
283+
private HexDumpConverter(String extension) {
284+
this.extension = extension;
285+
}
286+
287+
@Override
288+
public String convert(byte[] derOctetString, X509Certificate certificate) {
289+
return extension + " = " + hexDump(0, derOctetString);
290+
}
291+
}
292+
229293
}

0 commit comments

Comments
 (0)