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

solved issue "certutil: large passwords not set" #30944 #36689

Merged
merged 8 commits into from
Aug 2, 2021

Conversation

MiguelFerreira1998
Copy link
Contributor

Older versions of OpenSSL couldn't support passwords for a new Certificate Authority larger than 50 characters. I check the current version of the user and i prompt a warn message if they input a password longer than 50 and they are using OpenSLL under version 1.1.0

Fixed the issue about passwords longer than 50 not working on older versions of OpenSSL. From now on, users get an alert when they try to put a password with length above 50 and they have an OpenSSL version lower than 1.1.0, giving then the opportunity ti prompt one password again.
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security

(warning for all versions)
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.

Hi @MiguelFerreira1998 and @bedgarone

Thanks for your contribution on this issue. I've left some suggestions.

});
}
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like all of this section is whitespace changes (extra blank lines, additional indentation) that aren't needed.

return body.apply(promptedValue);
} finally {
Arrays.fill(promptedValue, (char) 0);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The withPassword method is called every time we need a password, even if it's being used to read a certificate file.
In that case we don't want to print this warning, because that would cause additional output (and an additional prompt) for simple things like reading a CA file that has a long password.

We need to only perform this check/warning if the password is being applied to a new file.
I'm OK if we want get rid of the promptYesNo and just print out a warning, but we only want to do either of them when we know the password is being used to write a file.

}
else{
long_size = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The formatting of thise code (spaces around brackets etc) is different to the way the rest of this source code is formatted. By the time we get to the end of this review process, we'll want to have it formatted in the same style as the surrounding code.

@MiguelFerreira1998
Copy link
Contributor Author

Thanks @tvernum for all the support. I will be committing what i think its a fix.

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.

I left some more feedback.

Arrays.fill(promptedValue, (char) 0);
while(long_size){
if(promptedValue.length > MAX_SIZE_PW_BUFFER_OLDER_SSL){
if(terminal.promptYesNo("Your password exceeds a length of 50 characters. Versions of OpenSSL older than 1.1.0 will not be able to use this certificate. Do you want to continue?", true)){
Copy link
Contributor

Choose a reason for hiding this comment

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

Having through about this a bit more, I think the prompt is going to be annoying rather than helpful.
I think we'd be better off just printing out a warning message, and continuing on.

Sorry for messing things around like this, but sometimes things become clearer during the review cycle.

@@ -381,7 +381,7 @@ CAInfo generateCA(Terminal terminal, OptionSet options) throws Exception {
return new CAInfo(caCert, keyPair.getPrivate(), true, password);
}
if (options.has(caPasswordSpec)) {
return withPassword("CA Private key", null, terminal, p -> new CAInfo(caCert, keyPair.getPrivate(), true, p.clone()));
return withPassword("CA Private key",false, null, terminal, p -> new CAInfo(caCert, keyPair.getPrivate(), true, p.clone()));
Copy link
Contributor

Choose a reason for hiding this comment

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

This one should be true.
We want to check the password length any time we're generating a new private key.

@@ -527,7 +527,8 @@ static void writeCAInfo(ZipOutputStream outputStream, CAInfo info, Terminal term
final String dirName = createCaDirectory(outputStream);
final String fileName = dirName + "ca.p12";
outputStream.putNextEntry(new ZipEntry(fileName));
withPassword("Generated CA", info.password, terminal, caPassword -> {

withPassword("Generated CA", false, info.password, terminal, caPassword -> {
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 this needs to be true as well.

@@ -794,7 +797,8 @@ void generateAndWriteSignedCertificates(Path output, boolean writeZipFile, Optio
final String keyFileName = entryBase + ".key";
outputStream.putNextEntry(new ZipEntry(keyFileName));
if (usePassword) {
withPassword(keyFileName, outputPassword, terminal, password -> {

withPassword(keyFileName, false, outputPassword, terminal, password -> {
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 this one needs to be true

@@ -923,15 +927,29 @@ private static PEMEncryptor getEncrypter(char[] password) {
return new JcePEMEncryptorBuilder("DES-EDE3-CBC").setProvider(BC_PROV).build(password);
}

private static <T, E extends Exception> T withPassword(String description, char[] password, Terminal terminal,
private static <T, E extends Exception> T withPassword(String description, boolean long_size, char[] password, Terminal terminal,
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than long_size, it would be better to name this parameter something like forNewKey so it describes the logical purpose of the parameter.

@tvernum
Copy link
Contributor

tvernum commented Jul 30, 2021

@elasticmachine test this please

@tvernum
Copy link
Contributor

tvernum commented Jul 30, 2021

@ywangd Can you do a quick review of my additions to this PR?

@tvernum tvernum requested a review from ywangd July 30, 2021 04:17
String wrongPassword = randomAlphaOfLengthBetween(8, 20);
terminal.addSecretInput(wrongPassword);
terminal.addSecretInput("__" + wrongPassword);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't really related to this PR, but I noticed it was a gap in testing.

Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

LGTM. But the PR description seems to be off:

I check the current version of the user and i prompt a warn message if they input a password longer than 50 and they are using OpenSLL under version 1.1.0

Only the password length is checked and warning is issued regardless. There is no check for OpenSSL version and in fact it is not viable to do so. If my understand is correct, I suggest we update the description before merge.

Comment on lines +936 to +940
"Warning: Your password exceeds "
+ MAX_PASSWORD_OLD_OPENSSL
+ " characters. Versions of OpenSSL older than "
+ OLD_OPENSSL_VERSION
+ " may not be able to read this file."
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"Warning: Your password exceeds "
+ MAX_PASSWORD_OLD_OPENSSL
+ " characters. Versions of OpenSSL older than "
+ OLD_OPENSSL_VERSION
+ " may not be able to read this file."
"Warning: Your password exceeds ["
+ MAX_PASSWORD_OLD_OPENSSL
+ "] characters. Versions of OpenSSL older than ["
+ OLD_OPENSSL_VERSION
+ "] may not be able to read this file."

Copy link
Contributor

Choose a reason for hiding this comment

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

Why? They're constants, so we don't need the braces in order to see where the variable part is substituted in.

Copy link
Member

Choose a reason for hiding this comment

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

I thought the braces are for emphasis. But if they are just for variables, then you are right that we don't need them here.

@@ -924,16 +929,43 @@ static PEMEncryptor getEncrypter(char[] password) {
return new JcePEMEncryptorBuilder("AES-128-CBC").setProvider(BC_PROV).build(password);
}

private static <T, E extends Exception> T withPassword(String description, char[] password, Terminal terminal,
static boolean checkPasswordLengthForOpenSSLCompatibility(char[] password, Terminal terminal, boolean confirm) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit:
This method and parameter names confused me for a bit. They made me think that the behaviour when confirm is false should be return false if password is too long. But instead the default behaviour is return true unless user says otherwise and confirm is to let user have that say. Maybe:

Suggested change
static boolean checkPasswordLengthForOpenSSLCompatibility(char[] password, Terminal terminal, boolean confirm) {
static boolean maybeWarnAndConfirmPasswordLengthForOpenSSLCompatibility(char[] password, Terminal terminal, boolean confirmRequired) {

It is quite verbose, but it feels more accurate to me. I am also happy if you can come up with something better.

@tvernum tvernum self-assigned this Jul 30, 2021
@tvernum
Copy link
Contributor

tvernum commented Jul 30, 2021

@elasticmachine test this please 🙏

@tvernum tvernum merged commit 6ea0ca4 into elastic:master Aug 2, 2021
@tvernum
Copy link
Contributor

tvernum commented Aug 2, 2021

Resolves #30944

tvernum added a commit to tvernum/elasticsearch that referenced this pull request Aug 2, 2021
Older versions of OpenSSL (prior to 1.1.0) had a fixed 50 char buffer
for password input.
This means that keys (etc) encrypted with a password > 50 chars
cannot be used by old versions of OpenSSL.

This change adds warnings/prompts when creating encrypted files with
passwords longer than 50 characters in elasticsearch-certutil.

Backport of: elastic#36689

Co-authored-by: MiguelFerreira1998 <[email protected]>
elasticsearchmachine pushed a commit that referenced this pull request Aug 2, 2021
Older versions of OpenSSL (prior to 1.1.0) had a fixed 50 char buffer
for password input.
This means that keys (etc) encrypted with a password > 50 chars
cannot be used by old versions of OpenSSL.

This change adds warnings/prompts when creating encrypted files with
passwords longer than 50 characters in elasticsearch-certutil.

Backport of: #36689

Co-authored-by: MiguelFerreira1998 <[email protected]>

Co-authored-by: MiguelFerreira1998 <[email protected]>
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-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.