Strip empty lines from downloaded cert chains

This fixes the "insufficient data" issue on IBMs crypto implementation.
pull/61/head
Richard Körber 2018-03-21 23:14:08 +01:00
parent 2ac4e7b7fb
commit 3f901e9e18
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
4 changed files with 140 additions and 1 deletions

View File

@ -41,4 +41,5 @@ _acme4j_ is open source software. The source code is distributed under the terms
* I would like to thank Brian Campbell and all the other [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) developers. _acme4j_ would not exist without your excellent work. * I would like to thank Brian Campbell and all the other [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home) developers. _acme4j_ would not exist without your excellent work.
* Thanks to [Daniel McCarney](https://github.com/cpu) for his help with the ACME protocol, Pebble, and Boulder. * Thanks to [Daniel McCarney](https://github.com/cpu) for his help with the ACME protocol, Pebble, and Boulder.
* [Ulrich Krause](https://github.com/eknori) for his help to make _acme4j_ run on IBM Java VMs.
* I also like to thank [everyone who contributed to _acme4j_](https://github.com/shred/acme4j/graphs/contributors). * I also like to thank [everyone who contributed to _acme4j_](https://github.com/shred/acme4j/graphs/contributors).

View File

@ -233,7 +233,7 @@ public class DefaultConnection implements Connection {
throw new AcmeProtocolException("Unexpected content type: " + contentType); throw new AcmeProtocolException("Unexpected content type: " + contentType);
} }
try (InputStream in = conn.getInputStream()) { try (InputStream in = new TrimmingInputStream(conn.getInputStream())) {
CertificateFactory cf = CertificateFactory.getInstance("X.509"); CertificateFactory cf = CertificateFactory.getInstance("X.509");
return cf.generateCertificates(in).stream() return cf.generateCertificates(in).stream()
.map(c -> (X509Certificate) c) .map(c -> (X509Certificate) c)

View File

@ -0,0 +1,74 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2018 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.connector;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.ParametersAreNonnullByDefault;
/**
* Normalizes line separators in an InputStream. Converts all line separators to '\n'.
* Multiple line separators are compressed to a single line separator.
*/
@ParametersAreNonnullByDefault
public class TrimmingInputStream extends InputStream {
private final InputStream in;
private boolean wasLineSeparator = true;
/**
* Creates a new {@link TrimmingInputStream}.
*
* @param in
* {@link InputStream} to read from. Will be closed when this stream is
* closed.
*/
public TrimmingInputStream(InputStream in) {
this.in = in;
}
@Override
public int read() throws IOException {
int ch = in.read();
if (wasLineSeparator) {
while (isLineSeparator(ch)) {
ch = in.read();
}
}
wasLineSeparator = isLineSeparator(ch);
if (ch == '\r') {
ch = '\n';
}
return ch;
}
@Override
public void close() throws IOException {
in.close();
super.close();
}
/**
* Checks if the character is a line separator.
*/
private static boolean isLineSeparator(int ch) {
return ch == '\n' || ch == '\r';
}
}

View File

@ -0,0 +1,64 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2018 Richard "Shred" Körber
* http://acme4j.shredzone.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.shredzone.acme4j.connector;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
/**
* Unit tests for {@link TrimmingInputStream}.
*/
public class TrimmingInputStreamTest {
@Test
public void testEmpty() throws IOException {
String out = trimByStream("");
assertThat(out, is(""));
}
@Test
public void testTrim() throws IOException {
String out = trimByStream("\n\n"
+ "Gallia est omnis divisa in partes tres,\r\n\r\n\r\n"
+ "quarum unam incolunt Belgae, aliam Aquitani,\r\r\r\n\n"
+ "tertiam, qui ipsorum lingua Celtae, nostra Galli appellantur.");
assertThat(out, is("Gallia est omnis divisa in partes tres,\n"
+ "quarum unam incolunt Belgae, aliam Aquitani,\n"
+ "tertiam, qui ipsorum lingua Celtae, nostra Galli appellantur."));
}
/**
* Trims a string by running it through the {@link TrimmingInputStream}.
*/
private String trimByStream(String str) throws IOException {
StringBuilder out = new StringBuilder();
try (TrimmingInputStream in = new TrimmingInputStream(
new ByteArrayInputStream(str.getBytes(StandardCharsets.US_ASCII)))) {
int ch;
while ((ch = in.read()) >= 0) {
out.append((char) ch);
}
}
return out.toString();
}
}