Skip to content

Commit 092c227

Browse files
author
Roger Riggs
committedSep 30, 2020
8252523: Add ASN.1 Formatter to work with test utility HexPrinter
Reviewed-by: weijun
1 parent 06d8cf6 commit 092c227

File tree

5 files changed

+797
-10
lines changed

5 files changed

+797
-10
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package jdk.test.lib.hexdump;
25+
26+
import org.testng.Assert;
27+
import org.testng.annotations.Test;
28+
29+
import java.io.DataInputStream;
30+
import java.io.EOFException;
31+
import java.io.IOException;
32+
import java.io.InputStream;
33+
import java.nio.file.Files;
34+
import java.nio.file.Path;
35+
import java.util.Base64;
36+
37+
import static org.testng.Assert.*;
38+
39+
/*
40+
* @test
41+
* @summary ASN.1 formatting
42+
* @library /test/lib
43+
* @compile ASN1FormatterTest.java
44+
* @run testng jdk.test.lib.hexdump.ASN1FormatterTest
45+
*/
46+
@Test
47+
public class ASN1FormatterTest {
48+
private static final String DIR = System.getProperty("test.src", ".");
49+
50+
@Test
51+
static void testPEM() throws IOException {
52+
String certFile = "openssl.p12.pem";
53+
Path certPath = Path.of(DIR, certFile);
54+
System.out.println("certPath: " + certPath);
55+
56+
try (InputStream certStream = Files.newInputStream(certPath)) {
57+
while (certStream.read() != '\n') {
58+
// Skip first line "-----BEGIN CERTIFICATE-----"
59+
}
60+
// Mime decoder for Certificate
61+
InputStream wis = Base64.getMimeDecoder().wrap(certStream);
62+
DataInputStream is = new DataInputStream(wis);
63+
String result = ASN1Formatter.formatter().annotate(is);
64+
System.out.println(result);
65+
66+
Assert.assertEquals(result.lines().count(), 76, "Lines");
67+
Assert.assertEquals(result.lines().filter(s -> s.contains("SEQUENCE")).count(),24, "Sequences");
68+
Assert.assertEquals(result.lines().filter(s -> s.contains("OBJECT ID")).count(), 17, "ObjectIDs");
69+
Assert.assertEquals(result.lines().filter(s -> s.contains("UTCTIME")).count(), 2, "UTCTIME");
70+
Assert.assertEquals(result.lines().filter(s -> s.contains("BIT STRING")).count(), 3, "BitStrings");
71+
} catch (EOFException eof) {
72+
// done
73+
}
74+
}
75+
76+
@Test
77+
static void dumpPEM() throws IOException {
78+
String file = "openssl.p12.pem";
79+
Path path = Path.of(DIR, file);
80+
System.out.println("path: " + path);
81+
82+
try (InputStream certStream = Files.newInputStream(path)) {
83+
while (certStream.read() != '\n') {
84+
// Skip first line "-----BEGIN CERTIFICATE-----"
85+
}
86+
// Mime decoder for Certificate
87+
InputStream wis = Base64.getMimeDecoder().wrap(certStream);
88+
89+
HexPrinter p = HexPrinter.simple()
90+
.formatter(ASN1Formatter.formatter(), "; ", 100);
91+
String result = p.toString(wis);
92+
System.out.println(result);
93+
94+
Assert.assertEquals(result.lines().count(), 126, "Lines");
95+
Assert.assertEquals(result.lines().filter(s -> s.contains("SEQUENCE")).count(), 24, "Sequences");
96+
Assert.assertEquals(result.lines().filter(s -> s.contains("OBJECT ID")).count(), 17, "ObjectIDs");
97+
Assert.assertEquals(result.lines().filter(s -> s.contains("UTCTIME")).count(), 2, "UTCTIME");
98+
Assert.assertEquals(result.lines().filter(s -> s.contains("BIT STRING")).count(), 3, "BitStrings");
99+
} catch (EOFException eof) {
100+
// done
101+
}
102+
}
103+
104+
@Test
105+
static void testIndefinate() {
106+
byte[] bytes = {0x24, (byte) 0x80, 4, 2, 'a', 'b', 4, 2, 'c', 'd', 0, 0};
107+
HexPrinter p = HexPrinter.simple()
108+
.formatter(ASN1Formatter.formatter(), "; ", 100);
109+
String result = p.toString(bytes);
110+
System.out.println(result);
111+
112+
Assert.assertEquals(result.lines().filter(s -> s.contains("OCTET STRING [INDEFINITE]")).count(),
113+
1, "Indefinite length");
114+
Assert.assertEquals(result.lines().filter(s -> s.contains("; OCTET STRING [2]")).count(),
115+
2, "Octet Sequences");
116+
Assert.assertEquals(result.lines().filter(s -> s.contains("; END-OF-CONTENT")).count(),
117+
1, "end of content");
118+
}
119+
120+
@Test
121+
static void testMain() {
122+
String file = "openssl.p12.pem";
123+
Path path = Path.of(DIR, file);
124+
String[] args = { path.toString() };
125+
System.out.println("path: " + path);
126+
ASN1Formatter.main(args);
127+
}
128+
129+
}

‎test/lib-test/jdk/test/lib/hexdump/HexPrinterTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Object[][] builtinParams() {
7878
return new Object[][]{
7979
{"minimal", "", "%02x", 16, "", 64, HexPrinter.Formatters.NONE, ""},
8080
{"canonical", "%08x ", "%02x ", 16, "|", 31, HexPrinter.Formatters.PRINTABLE, "|" + System.lineSeparator()},
81-
{"simple", "%5d: ", "%02x ", 16, " // ", 64, HexPrinter.Formatters.ASCII, System.lineSeparator()},
81+
{"simple", "%04x: ", "%02x ", 16, " // ", 64, HexPrinter.Formatters.ASCII, System.lineSeparator()},
8282
{"source", " ", "(byte)%3d, ", 8, " // ", 64, HexPrinter.Formatters.PRINTABLE, System.lineSeparator()},
8383
};
8484
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDjjCCAnagAwIBAgIBAzANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJJTjEL
3+
MAkGA1UECAwCS0ExDzANBgNVBAoMBk9yYWNsZTENMAsGA1UECwwESmF2YTEQMA4G
4+
A1UEAwwHQ2xpZW50MTAeFw0xNTA1MjYyMjE3MThaFw0yNTA1MjMyMjE3MThaMEwx
5+
CzAJBgNVBAYTAklOMQswCQYDVQQIDAJLQTEPMA0GA1UECgwGT3JhY2xlMQ0wCwYD
6+
VQQLDARKYXZhMRAwDgYDVQQDDAdDbGllbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOC
7+
AQ8AMIIBCgKCAQEA2HADVMaKPd7xAYK0BTsCcQzglk8H2qp0Sg5nDYgb7KqB/1cb
8+
RyMB3g3FG4Isv6L0Lp2GLAeHVn35YljHNrcBUU5fG/+DNJPNiM+srevblMeksOcA
9+
frPnxmog+GMgiO97O2/3Xtgl0ailsOHidPH9hBXr+WikNu7ITPXkJiYi0d1n8p2N
10+
e/p4W4cBitxIUlZm2OTSW4d3EDW86saf657kSpTlb2zBT/r9fjWluHlTg+jGnGIz
11+
UdpYP7sSnye8oym5PxT2IMPU6vRgF9Gzwg+6bPaZnrYNURifGJIuQH+/wDaqA+Ix
12+
g2Q2Ij8SiDhkNrCoeLf77Aot9d5ZPtledJPSRQIDAQABo3sweTAJBgNVHRMEAjAA
13+
MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
14+
BgNVHQ4EFgQUhxNmvHpNjpjnl/vMVkEnyF5Msk0wHwYDVR0jBBgwFoAUHyFP2xAx
15+
0GeDCQPTzfxG7M8di7QwDQYJKoZIhvcNAQELBQADggEBAD4rXzKq8PdSK7rzuwfu
16+
q+RzeYZnNM7OsoBGhMfHQKnnI3LH5bgyttuCoV665X2mgy6+LZcrXqom/ZrLXQ6x
17+
JVtGxNHr7rqbnC/9tB2/s9HHN3YiRs966shWHGkhCubsUGre7Z25Pq55K6Pyl+nU
18+
hb+K8aQ54z4oDt+raAdbuILq91fUjw5j1qex3d62fHvf4IO3spcKY4HhnwBPifg2
19+
YZCiZRZOoVysi2FTdsvW2NfQCYgtUftbkfNrKglkRuIa9rQEduhDy1cwn4fc9S1f
20+
6WTvuJNoIp3o1nQppFjfO7fzfIDCrlaEkkXU7O54KQ5HTKu62tZp9xKW71oolOnZ
21+
bZQ=
22+
-----END CERTIFICATE-----

‎test/lib/jdk/test/lib/hexdump/ASN1Formatter.java

+627
Large diffs are not rendered by default.

‎test/lib/jdk/test/lib/hexdump/HexPrinter.java

+18-9
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ public final class HexPrinter {
162162
"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
163163
"can", "em", "sub", "esc", "fs", "gs", "rs", "us"
164164
};
165-
private static final String initOffsetFormat = "%5d: ";
166165
private static final int initBytesCount = 16; // 16 byte values
167166
private static final String initBytesFormat = "%02x ";
168167
private static final int initAnnoWidth = initBytesCount * 4;
@@ -265,7 +264,7 @@ public static HexPrinter canonical() {
265264
* to a multi-line string.
266265
* The parameters are set to:
267266
* <UL>
268-
* <LI>byte offset format: signed decimal width 5 and a space, {@code "%5d: "},
267+
* <LI>byte offset format: hexadecimal width 4, colon, and a space, {@code "%04x: "},
269268
* <LI>each byte value is formatted as 2 hex digits and a space: {@code "%02x "},
270269
* <LI>maximum number of byte values per line: {@value initBytesCount},
271270
* <LI>delimiter for the annotation: {@code " // "},
@@ -288,7 +287,7 @@ public static HexPrinter canonical() {
288287
* @return a new HexPrinter
289288
*/
290289
public static HexPrinter simple() {
291-
return new HexPrinter(Formatters.ASCII, initOffsetFormat,
290+
return new HexPrinter(Formatters.ASCII, "%04x: ",
292291
initBytesFormat, initBytesCount,
293292
initAnnoDelim, initAnnoWidth, System.lineSeparator(),
294293
System.out);
@@ -604,11 +603,14 @@ public HexPrinter withOffsetFormat(String offsetFormat) {
604603
* If the byteFormat is an empty String, there are no byte values in the output.
605604
*
606605
* @param byteFormat a format string for each byte
607-
* @param bytesCount the maximum number of byte values per line
606+
* @param bytesCount the maximum number of byte values per line; greater than zero
608607
* @return a new HexPrinter
608+
* @throws IllegalArgumentException if bytesCount is less than or equal to zero
609609
*/
610610
public HexPrinter withBytesFormat(String byteFormat, int bytesCount) {
611611
Objects.requireNonNull(bytesFormat, "bytesFormat");
612+
if (bytesCount <= 0)
613+
throw new IllegalArgumentException("bytesCount should be greater than zero");
612614
return new HexPrinter(annoFormatter, offsetFormat, byteFormat, bytesCount,
613615
annoDelim, annoWidth, lineSeparator, dest);
614616
}
@@ -946,6 +948,7 @@ private static final class AnnotationWriter extends CharArrayWriter {
946948
private final transient DataInputStream in;
947949
private final transient int baseOffset;
948950
private final transient HexPrinter params;
951+
private final transient int bytesSingleWidth;
949952
private final transient int bytesColWidth;
950953
private final transient int annoWidth;
951954
private final transient Appendable dest;
@@ -966,7 +969,8 @@ private static final class AnnotationWriter extends CharArrayWriter {
966969
this.source = new OffsetInputStream(source);
967970
this.source.mark(1024);
968971
this.in = new DataInputStream(this.source);
969-
this.bytesColWidth = params.bytesCount * String.format(params.bytesFormat, 255).length();
972+
this.bytesSingleWidth = String.format(params.bytesFormat, 255).length();
973+
this.bytesColWidth = params.bytesCount * bytesSingleWidth;
970974
this.annoWidth = params.annoWidth;
971975
this.dest = dest;
972976
}
@@ -1062,11 +1066,16 @@ private void process() {
10621066
int count = source.markedByteCount();
10631067
try {
10641068
source.reset();
1065-
long binColOffset = source.byteOffset();
1069+
int binColOffset = (int)source.byteOffset();
10661070
while (count > 0 || info.length() > 0) {
1067-
dest.append(String.format(params.offsetFormat, binColOffset + baseOffset));
1068-
int colWidth = 0;
1069-
int byteCount = Math.min(params.bytesCount, count);
1071+
int offset = binColOffset + baseOffset; // offset of first byte on the line
1072+
dest.append(String.format(params.offsetFormat, offset));
1073+
// Compute indent based on offset modulo bytesCount
1074+
int colOffset = offset % params.bytesCount;
1075+
int colWidth = colOffset * bytesSingleWidth;
1076+
dest.append(" ".repeat(colWidth));
1077+
// Append the bytes that fit on this line
1078+
int byteCount = Math.min(params.bytesCount - colOffset, count);
10701079
for (int i = 0; i < byteCount; i++) {
10711080
int b = source.read();
10721081
if (b == -1)

0 commit comments

Comments
 (0)
Please sign in to comment.