Skip to content

Conversation

@abvaidya
Copy link
Contributor

@abvaidya abvaidya commented Jul 14, 2024

fixes #6572

Instead of parsing the inputStream ourselves, we should let the underlying CertificateFactory implementation process it and return list of certificates.

@abvaidya abvaidya requested a review from a team July 14, 2024 23:37
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Jul 14, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: abvaidya / name: Abhijeet V (98830eb)
  • ✅ login: evantorrie / name: ET (71a7702)

@codecov
Copy link

codecov bot commented Jul 14, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.60%. Comparing base (3fa57f9) to head (98830eb).
Report is 8 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6579      +/-   ##
============================================
- Coverage     90.62%   90.60%   -0.03%     
- Complexity     6261     6262       +1     
============================================
  Files           689      690       +1     
  Lines         18704    18706       +2     
  Branches       1844     1846       +2     
============================================
- Hits          16951    16948       -3     
- Misses         1198     1199       +1     
- Partials        555      559       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

// 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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote a test case for this, but was surprised that it passes on the main branch. Not sure why it would pass if this was required for handle explanatory text:

  @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";

  /**
   * 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);

    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)));
  }

Copy link
Contributor Author

@abvaidya abvaidya Jul 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely faced this problem with our internal certificate bundle, but after your comment, I debugged a little more and I am wondering if the bundle was not created correctly.
When I iterated using our internal bundle with the main branch code, it added 12 certificates correctly ( even with the explanatory text ) but at the end there was one byte which ended up throwing "empty input" error.

So main branch code is able to handle explanatory text but cf.generateCertificates(is) is a little more forgiving.
I completely understand if you prefer to not merge this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy enough with switching to cf.generateCertificates(is) if its a more robust parsing solution, but just need to demonstrate that with some test case. I.e. some certificate that fails with the logic on main but succeeds when this logic is applied.

Files.write(
certificate,
"\n".getBytes(StandardCharsets.UTF_8),
StandardOpenOption.APPEND);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correct, the approach in this PR of using factory.generateCertificates(is) is able to handle a trailing line break where as the approach on main can not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that is correct.

@abvaidya abvaidya force-pushed the issue-6572 branch 2 times, most recently from a1972c1 to 71a7702 Compare July 19, 2024 21:12
@abvaidya
Copy link
Contributor Author

I reordered the commits and removed my "fix" commit. This should fail the test with main branch code.

@abvaidya
Copy link
Contributor Author

abvaidya commented Jul 19, 2024

As expected, the main branch code is failing with current test.

Caused by: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
    	at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:110)
    	at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
    	at io.opentelemetry.exporter.internal.TlsUtil.keyManager(TlsUtil.java:85)
    	... 148 more
    Caused by: java.io.IOException: Empty input
    	at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:106)
    	... 150 more
    "
        at io.opentelemetry.exporter.internal.TlsUtilTest.keyManager_CertWithExplanatoryText(TlsUtilTest.java:103)

@abvaidya
Copy link
Contributor Author

Thank you @jack-berg for the original test and @evantorrie for helping to reproduce the issue.

@jack-berg jack-berg merged commit 468b528 into open-telemetry:main Jul 22, 2024
breedx-splk pushed a commit to breedx-splk/opentelemetry-java that referenced this pull request Aug 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support PEM trust bundles with explanatory text in it

3 participants