Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add KeyUsage, ExtendedKeyUsage, CipherSuite & Protocol to SSL diagnos… #65634

Merged
merged 5 commits into from
Aug 16, 2021

Conversation

sindhusp
Copy link
Contributor

@sindhusp sindhusp commented Nov 30, 2020

Closes #63784

@cla-checker-service
Copy link

cla-checker-service bot commented Nov 30, 2020

💚 CLA has been signed

@sindhusp
Copy link
Contributor Author

Hi @tvernum , I signed the Contributor Agreement successfully, but that check is failing on my PR. Any thoughts on what I could do to verify the signing?

@tvernum tvernum self-requested a review December 1, 2020 04:48
@tvernum
Copy link
Contributor

tvernum commented Dec 1, 2020

@sindhusp The issue seems to be that the email address you used in your git commit is not the same email address as you used to sign the CLA.
and your commit doesn't link back to your GitHub account so we can't verify it based on your github userid.

Specifically your CLA has a gmail address, but your commit has a zeta.tech address.
And, it doesn't look like GitHub knows about your zeta.tech address either, so it doesn't know that this: sindhusp@3d85623 is you - the author on that commit is just a name, but if you compare it to one of my commits GitHub knows that it's me, and links it to my GitHub account.

I think what you need to do is make sure your GitHub profile has both your zeta.tech email address and your GMail address.

@elasticmachine elasticmachine added the Team:Security Meta label for security team label Dec 1, 2020
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (Team:Security)

Copy link
Contributor

@tvernum tvernum left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution, I have some suggested changes.


private static String keyUsageDescription(X509Certificate certificate) {
return Optional.ofNullable(certificate.getKeyUsage())
.map(keyUsage -> "keyUsage [" + Arrays.toString(keyUsage) + "]")
Copy link
Contributor

Choose a reason for hiding this comment

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

getKeyUsage() returns boolean[], but we need to decode it into the actual usage types (see the Javadoc for getKeyUsage for a description of each index)
Output like

keyUsage [true,true,false,false,true,false,true,false,false]

isn't explanatory enough for this diagnostic message.

@@ -178,7 +179,13 @@ public static String getTrustDiagnosticFailure(X509Certificate[] chain, PeerType
.append(" provided a certificate with subject name [")
.append(peerCert.getSubjectX500Principal().getName())
.append("] and ")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.append("] and ")
.append("], ")

@@ -178,7 +179,13 @@ public static String getTrustDiagnosticFailure(X509Certificate[] chain, PeerType
.append(" provided a certificate with subject name [")
.append(peerCert.getSubjectX500Principal().getName())
.append("] and ")
.append(fingerprintDescription(peerCert));
.append(fingerprintDescription(peerCert))
.append(" and ")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.append(" and ")
.append(", ")

}

private static String generateExtendedKeyUsageDescription(List<String> list) {
return list.stream()
Copy link
Contributor

Choose a reason for hiding this comment

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

getExtendedKeyUsage() returns a List of OIDs.
For the standard OIDs (defined here https://tools.ietf.org/html/rfc5280#page-44), we need to decode those OIDs into useful names.
Non standard OIDs should be left in their dotted notation.

private static void addSessionDescription(SSLSession session, StringBuilder message) {
String cipherSuite = Optional.ofNullable(session).map(SSLSession::getCipherSuite).orElse("<unknown cipherSuite>");
String protocol = Optional.ofNullable(session).map(SSLSession::getProtocol).orElse("<unknown protocol>");
message.append("; the session supports the cipher suite [")
Copy link
Contributor

Choose a reason for hiding this comment

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

For brevity we can omit articles from the diagnostic

Suggested change
message.append("; the session supports the cipher suite [")
message.append("; the session supports cipher suite [")

Comment on lines 445 to 450
.append("] and ")
.append("the protocol [")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.append("] and ")
.append("the protocol [")
.append("] and protocol [")

@@ -63,7 +63,8 @@ public void testDiagnosticMessageWhenServerProvidesAFullCertChainThatIsTrusted()
final String message = SslDiagnostics.getTrustDiagnosticFailure(chain, SslDiagnostics.PeerType.SERVER, session,
"xpack.http.ssl", trustIssuers);
assertThat(message, Matchers.equalTo("failed to establish trust with server at [192.168.1.1];" +
" the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050];" +
" the server provided a certificate with subject name [CN=cert1] and fingerprint [3bebe388a66362784afd6c51a9000961a4e10050] and no keyUsage and no extendedKeyUsage;" +
" the session supports the cipher suite [<unknown cipherSuite>] and the protocol [<unknown protocol>];" +
Copy link
Contributor

Choose a reason for hiding this comment

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

We need some of the tests to have real values for all of these.
As it is we're only testing the "no value" cases, which is the least important case.

That will require regenerating some of the certs (and updating the fingerprints) to have key usage properties.
(see libs/ssl-config/src/test/resources/certs/README.txt)
and/or changing mockCertificateWithIssuer and session to provide mock values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've edited the mockCertificateWithIssuer and session methods to provide mock values. I attempted to regenerate the cert yesterday without much success, so went with the mocking. Let me know if this works.

@sindhusp
Copy link
Contributor Author

sindhusp commented Dec 1, 2020

@tvernum thanks, my CLA problem is sorted, I've amended my commit to point to my gmail ID.
Thanks for the quick review, I'm addressing your comments.

* Fix formatting
* Add descriptive keyUsage, extendedKeyUsage msgs
* Mock cert's keyUsage, extendedKeyUsage
* Mock session's cipherSuite, protocol
@sindhusp
Copy link
Contributor Author

sindhusp commented Dec 1, 2020

@tvernum, I have addressed your comments. Please let me know if you have more suggestions.

return "no keyUsage";
}

final String[] keyUsageGlossary = {"digitalSignature", "nonRepudiation", "keyEncipherment",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I use an enum here too like I've done with ExtendedKeyUsage, for uniformity? I could define the index as the Enum field.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think either is fine.
I do like the consistency of having an enum for each, but it would require care so that the ordinals matched correctly.

I think my personal preference would be to just move this array to be a constant that is declared in the same part of the file as ExtendedKeyUsage

@sindhusp sindhusp requested a review from tvernum December 1, 2020 18:07
@sindhusp
Copy link
Contributor Author

sindhusp commented Dec 4, 2020

A little nudge for review @tvernum :)

@sindhusp
Copy link
Contributor Author

@tvernum bump for review.. Is it okay to remind this way? Is there someone else I can loop in for this PR?

@tvernum
Copy link
Contributor

tvernum commented Dec 23, 2020

He @sindhusp, Pinging here is fine but we're just a bit short of time at the moment and this PR has had to take a back seat. I hope to have time next week.

@tvernum
Copy link
Contributor

tvernum commented Feb 9, 2021

Hi @sindhusp Sorry for taking so long on this - can you let me know if you're still interested in working on this?

If you don't have time, then someone from Elastic can finish it.


public static String decodeOid(String oid) {
for (ExtendedKeyUsage e : values()) {
if (e.oid != null && e.oid.equals(oid)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

e.oid can never be null, because this is an enum with fixed (non-null) values.
I think it's fine to skip the null check here.

If you'd prefer to be safe, you could use this.oid = Objects.requireNonNull(oid); in the constructor.

return "no keyUsage";
}

final String[] keyUsageGlossary = {"digitalSignature", "nonRepudiation", "keyEncipherment",
Copy link
Contributor

Choose a reason for hiding this comment

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

I think either is fine.
I do like the consistency of having an enum for each, but it would require care so that the ordinals matched correctly.

I think my personal preference would be to just move this array to be a constant that is declared in the same part of the file as ExtendedKeyUsage

List<String> keyUsageDescription = new ArrayList<>();
IntStream.range(0, keyUsage.length).forEach(i -> {
if (keyUsage[i]) {
keyUsageDescription.add(keyUsageGlossary[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

For safety we should check that i < keyUsageGlossary.length

Comment on lines 452 to 459
List<String> keyUsageDescription = new ArrayList<>();
IntStream.range(0, keyUsage.length).forEach(i -> {
if (keyUsage[i]) {
keyUsageDescription.add(keyUsageGlossary[i]);
}
});
return keyUsageDescription.stream()
.reduce((a, b) -> a + ", " + b)
Copy link
Contributor

Choose a reason for hiding this comment

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

The style use have used here is fine, but I would have written it like this:

Suggested change
List<String> keyUsageDescription = new ArrayList<>();
IntStream.range(0, keyUsage.length).forEach(i -> {
if (keyUsage[i]) {
keyUsageDescription.add(keyUsageGlossary[i]);
}
});
return keyUsageDescription.stream()
.reduce((a, b) -> a + ", " + b)
String keyUsageDescription = IntStream.range(0, keyUsage.length)
.filter(i -> keyUsage[i])
.map(i -> i < keyUsageGlossary.length ? keyUsageGlossary[i] : "#" + i)
.collect(Collectors.joining(", "));

And then tested whether that was empty or not.

String protocol = Optional.ofNullable(session)
.map(SSLSession::getProtocol)
.orElse("<unknown protocol>");
message.append("; the session supports cipher suite [")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
message.append("; the session supports cipher suite [")
message.append("; the session uses cipher suite [")

Strictly, by the time we get to a session being established it's not really "supports", it's "has selected for use"

@sindhusp
Copy link
Contributor Author

sindhusp commented Mar 5, 2021

@tvernum thanks for the comments, I didn't see it earlier. I shall address them today.

@tvernum
Copy link
Contributor

tvernum commented Aug 13, 2021

@elasticmachine test this please 🙏

@tvernum tvernum self-assigned this Aug 13, 2021
@tvernum
Copy link
Contributor

tvernum commented Aug 13, 2021

@elasticmachine test this please 🙏

@tvernum tvernum requested a review from jkakavas August 13, 2021 07:13
@tvernum
Copy link
Contributor

tvernum commented Aug 13, 2021

@jkakavas I made some tweaks to this PR - can you give it a quick look?

Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

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

LGTM, double checked key usage and extended key usage in relevant RFCs and messaging looks fine to me

@tvernum tvernum merged commit f4e3f33 into elastic:master Aug 16, 2021
tvernum added a commit to tvernum/elasticsearch that referenced this pull request Aug 16, 2021
…stics

This commit extends the SSL diagnostics message to include descriptions of the

- The KeyUsage and ExtendedKeyUsage of the peer's certificate
- The CipherSuite & Protocol (TLS/SSL version) of the current session

These can be helpful in diagnosing SSL errors.

Co-authored-by: Tim Vernum <tim@adjective.org>

Backport of: elastic#65634
wjp719 added a commit to wjp719/elasticsearch that referenced this pull request Aug 17, 2021
* master: (868 commits)
  Query API key - Rest spec and yaml tests (elastic#76238)
  Delay shard reassignment from nodes which are known to be restarting (elastic#75606)
  Reenable bwc tests for elastic#76475 (elastic#76576)
  Set version to 7.15 in BWC code (elastic#76577)
  Don't remove warning headers on all failure (elastic#76434)
  Disable bwc tests for elastic#76475 (elastic#76541)
  Re-enable bwc tests (elastic#76567)
  Keep track of data recovered from snapshots in RecoveryState (elastic#76499)
  [Transform] Align transform checkpoint range with date_histogram interval for better performance (elastic#74004)
  EQL: Remove "wildcard" function (elastic#76099)
  Fix 'accept' and 'content_type' fields for search_mvt API
  Add persistent licensed feature tracking (elastic#76476)
  Add system data streams to feature state snapshots (elastic#75902)
  fix the error message for instance methods that don't exist (elastic#76512)
  ILM: Add validation of the number_of_shards parameter in Shrink Action of ILM (elastic#74219)
  remove dashboard only reserved role (elastic#76507)
  Fix Stack Overflow in UnassignedInfo in Corner Case (elastic#76480)
  Add (Extended)KeyUsage KeyUsage, CipherSuite & Protocol to SSL diagnostics (elastic#65634)
  Add recovery from snapshot to tests (elastic#76535)
  Reenable BwC Tests after elastic#76532 (elastic#76534)
  ...
@sindhusp sindhusp deleted the sslDiagnostics branch February 19, 2023 10:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>enhancement :Security/TLS SSL/TLS, Certificates Team:Security Meta label for security team v7.15.0 v8.0.0-alpha2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add KeyUsage, ExtendedKeyUsage, CipherSuite & Protocol to SSL diagnostics
8 participants