Skip to content

Commit

Permalink
Use generateCertificates() of CertificateFactory to process certifica…
Browse files Browse the repository at this point in the history
…tes (open-telemetry#6579)

Signed-off-by: Abhijeet V <[email protected]>
Co-authored-by: ET <[email protected]>
  • Loading branch information
abvaidya and evantorrie authored Jul 22, 2024
1 parent 685a378 commit 468b528
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
Expand Down Expand Up @@ -77,14 +76,11 @@ public static X509KeyManager keyManager(byte[] privateKeyPem, byte[] certificate
PrivateKey key = generatePrivateKey(keySpec, SUPPORTED_KEY_FACTORIES);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

List<Certificate> chain = new ArrayList<>();

ByteArrayInputStream is = new ByteArrayInputStream(certificatePem);
while (is.available() > 0) {
chain.add(cf.generateCertificate(is));
}

// pass the input stream to generateCertificates to get a list of certificates
// generateCertificates can handle multiple certificates in a single input stream
// including PEM files with explanatory text
List<? extends Certificate> chain = (List<? extends Certificate>) cf.generateCertificates(is);
ks.setKeyEntry("trusted", key, "".toCharArray(), chain.toArray(new Certificate[] {}));

KeyManagerFactory kmf =
Expand Down Expand Up @@ -126,9 +122,13 @@ public static X509TrustManager trustManager(byte[] trustedCertificatesPem) throw
ByteArrayInputStream is = new ByteArrayInputStream(trustedCertificatesPem);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
int i = 0;
while (is.available() > 0) {
X509Certificate cert = (X509Certificate) factory.generateCertificate(is);
ks.setCertificateEntry("cert_" + i, cert);
// pass the input stream to generateCertificates to get a list of certificates
// generateCertificates can handle multiple certificates in a single input stream
// including PEM files with explanatory text
List<? extends Certificate> certificates =
(List<? extends Certificate>) factory.generateCertificates(is);
for (Certificate certificate : certificates) {
ks.setCertificateEntry("cert_" + i, certificate);
i++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,36 @@
import static org.assertj.core.api.Assertions.assertThatCode;

import com.linecorp.armeria.internal.common.util.SelfSignedCertificate;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.KeyFactory;
import java.security.cert.CertificateException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.stream.Stream;
import javax.net.ssl.SSLException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

class TlsUtilTest {

@TempDir private Path tempDir;

private static final String EXPLANATORY_TEXT =
"Subject: CN=Foo\n"
+ "Issuer: CN=Foo\n"
+ "Validity: from 7/9/2012 3:10:38 AM UTC to 7/9/2013 3:10:37 AM UTC\n";

private SelfSignedCertificate rsaCertificate;
private SelfSignedCertificate ecCertificate;

Expand Down Expand Up @@ -60,4 +78,36 @@ void generatePrivateKey_Invalid() {
.isInstanceOf(SSLException.class)
.hasMessage("Unable to generate key from supported algorithms: [EC]");
}

/**
* Append <a href="https://datatracker.ietf.org/doc/html/rfc7468#section-5.2">explanatory text</a>
* prefix and verify {@link TlsUtil#keyManager(byte[], byte[])} succeeds.
*/
@ParameterizedTest
@MethodSource("keyManagerArgs")
void keyManager_CertWithExplanatoryText(SelfSignedCertificate selfSignedCertificate)
throws IOException {
Path certificate = tempDir.resolve("certificate");
Files.write(certificate, EXPLANATORY_TEXT.getBytes(StandardCharsets.UTF_8));
Files.write(
certificate,
com.google.common.io.Files.toByteArray(selfSignedCertificate.certificate()),
StandardOpenOption.APPEND);
Files.write(certificate, "\n".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);

assertThatCode(
() ->
TlsUtil.keyManager(
com.google.common.io.Files.toByteArray(selfSignedCertificate.privateKey()),
com.google.common.io.Files.toByteArray(new File(certificate.toString()))))
.doesNotThrowAnyException();
}

private static Stream<Arguments> keyManagerArgs() throws CertificateException {
Instant now = Instant.now();
return Stream.of(
Arguments.of(
new SelfSignedCertificate(Date.from(now), Date.from(now), "RSA", 2048),
new SelfSignedCertificate(Date.from(now), Date.from(now), "EC", 256)));
}
}

0 comments on commit 468b528

Please sign in to comment.