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
8277474: jarsigner does not check if algorithm parameters are disabled #7582
Changes from 1 commit
70da21b
9ffda80
224bf18
516d8bf
2a73d1e
d2cd7ef
74dc704
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ | |
import java.net.URLClassLoader; | ||
import java.security.cert.CertPathValidatorException; | ||
import java.security.cert.PKIXBuilderParameters; | ||
import java.security.spec.PSSParameterSpec; | ||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
import java.util.zip.*; | ||
|
@@ -1021,6 +1022,8 @@ void verifyJar(String jarName) | |
si.getDigestAlgorithmId(), | ||
si.getDigestEncryptionAlgorithmId(), | ||
si.getAuthenticatedAttributes() == null); | ||
AlgorithmId encAlgId = si.getDigestEncryptionAlgorithmId(); | ||
AlgorithmParameters sigAlgParams = encAlgId.getParameters(); | ||
PublicKey key = signer.getPublicKey(); | ||
PKCS7 tsToken = si.getTsToken(); | ||
if (tsToken != null) { | ||
|
@@ -1035,6 +1038,8 @@ void verifyJar(String jarName) | |
tsSi.getDigestAlgorithmId(), | ||
tsSi.getDigestEncryptionAlgorithmId(), | ||
tsSi.getAuthenticatedAttributes() == null); | ||
AlgorithmId tsEncAlgId = tsSi.getDigestEncryptionAlgorithmId(); | ||
AlgorithmParameters tsSigAlgParams = tsEncAlgId.getParameters(); | ||
Calendar c = Calendar.getInstance( | ||
TimeZone.getTimeZone("UTC"), | ||
Locale.getDefault(Locale.Category.FORMAT)); | ||
|
@@ -1049,22 +1054,22 @@ void verifyJar(String jarName) | |
history = String.format( | ||
rb.getString("history.with.ts"), | ||
signer.getSubjectX500Principal(), | ||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp), | ||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp), | ||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp, null), | ||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp, sigAlgParams), | ||
verifyWithWeak(key, jcp), | ||
c, | ||
tsSigner.getSubjectX500Principal(), | ||
verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true, jcpts), | ||
verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true, jcpts), | ||
verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true, jcpts, null), | ||
verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true, jcpts, tsSigAlgParams), | ||
verifyWithWeak(tsKey, jcpts)); | ||
} else { | ||
JarConstraintsParameters jcp = | ||
new JarConstraintsParameters(chain, null); | ||
history = String.format( | ||
rb.getString("history.without.ts"), | ||
signer.getSubjectX500Principal(), | ||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp), | ||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp), | ||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false, jcp, null), | ||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false, jcp, sigAlgParams), | ||
verifyWithWeak(key, jcp)); | ||
} | ||
} catch (Exception e) { | ||
|
@@ -1393,17 +1398,25 @@ private void displayMessagesAndResult(boolean isSigning) { | |
} | ||
|
||
private String verifyWithWeak(String alg, Set<CryptoPrimitive> primitiveSet, | ||
boolean tsa, JarConstraintsParameters jcp) { | ||
boolean tsa, JarConstraintsParameters jcp, AlgorithmParameters algParams) { | ||
|
||
try { | ||
JAR_DISABLED_CHECK.permits(alg, jcp, false); | ||
} catch (CertPathValidatorException e) { | ||
disabledAlgFound = true; | ||
return String.format(rb.getString("with.disabled"), alg); | ||
} | ||
if (algParams != null) { | ||
try { | ||
JAR_DISABLED_CHECK.permits(algParams, jcp); | ||
} catch (CertPathValidatorException e) { | ||
disabledAlgFound = true; | ||
return String.format(rb.getString("with.disabled"), algParams); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return value of this method will be shown as the "Signature algorithm" in the output. It's OK to include an optional "weak" (or "disabled") tag, but the core part still must be an algorithm name. Here, the updated code returns the string format of I'm not sure how to fix this nicely. Certainly you want to show the user why it is weak so the weak part should be displayed. A verbose solution could be "RSASSA-PSS using PSSParameterSpec(...SHA-1...) (weak)", but the Same comment to the code change below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I add "RSSSSA-PSS using “ to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does it look like now? Also, you might need to create a mapping in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what if it's another algorithm using another type of parameters? You cannot hardcode "RSASSA-PSS" and take it for granted that there is a "]" inside the string format of the parameter and it's the end of the weak part. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made change to add "RSASSA-PSS using” before its parameter output when the signature algorithm is RSASSA-PSS. Also, keep the parameter string without doing further parsing and stripping off based on the "]". |
||
} | ||
} | ||
|
||
try { | ||
LEGACY_CHECK.permits(alg, jcp, false); | ||
return alg; | ||
} catch (CertPathValidatorException e) { | ||
if (primitiveSet == SIG_PRIMITIVE_SET) { | ||
legacyAlg |= 2; | ||
|
@@ -1419,6 +1432,17 @@ private String verifyWithWeak(String alg, Set<CryptoPrimitive> primitiveSet, | |
} | ||
return String.format(rb.getString("with.weak"), alg); | ||
} | ||
if (algParams != null) { | ||
try { | ||
LEGACY_CHECK.permits(algParams, jcp); | ||
return alg; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to return here since it will be returned on line 1445 anyway. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed. |
||
} catch (CertPathValidatorException e) { | ||
legacyAlg |= 2; | ||
legacySigAlg = alg; | ||
return String.format(rb.getString("with.weak"), algParams); | ||
} | ||
} | ||
return alg; | ||
} | ||
|
||
private String verifyWithWeak(PublicKey key, JarConstraintsParameters jcp) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code 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. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
* @test | ||
* @bug 8277474 | ||
* @summary jarsigner -verify should check if the algorithm parameters of | ||
* its signature algorithm use disabled or legacy algorithms | ||
* @library /test/lib | ||
* @modules java.base/sun.security.x509 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, removed it. Thanks for the review! |
||
*/ | ||
|
||
import jdk.test.lib.SecurityTools; | ||
import jdk.test.lib.process.OutputAnalyzer; | ||
import jdk.test.lib.util.JarUtils; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
|
||
public class CheckAlgParams { | ||
private static final String JAVA_SECURITY_FILE = "java.security"; | ||
|
||
public static void main(String[] args) throws Exception{ | ||
|
||
SecurityTools.keytool("-keystore ks -storepass changeit " + | ||
"-genkeypair -keyalg RSASSA-PSS -alias ca -dname CN=CA " + | ||
"-ext bc:c") | ||
.shouldHaveExitValue(0); | ||
|
||
JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("ks")); | ||
|
||
SecurityTools.jarsigner("-keystore ks -storepass changeit " + | ||
"-signedjar signeda.jar " + | ||
"-verbose" + | ||
" a.jar ca") | ||
.shouldHaveExitValue(0); | ||
|
||
Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), | ||
"jdk.jar.disabledAlgorithms=SHA256\n" + | ||
"jdk.security.legacyAlgorithms=\n"); | ||
|
||
SecurityTools.jarsigner("-verify signeda.jar " + | ||
"-J-Djava.security.properties=" + | ||
JAVA_SECURITY_FILE + | ||
" -keystore ks -storepass changeit -verbose -debug") | ||
.shouldMatch("Digest algorithm: SHA-256.*(disabled)") | ||
.shouldMatch("Signature algorithm: PSSParameterSpec.*hashAlgorithm=SHA-256.*(disabled)") | ||
.shouldContain("The jar will be treated as unsigned") | ||
.shouldHaveExitValue(0); | ||
|
||
Files.deleteIfExists(Paths.get(JAVA_SECURITY_FILE)); | ||
Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), | ||
"jdk.jar.disabledAlgorithms=\n" + | ||
"jdk.security.legacyAlgorithms=SHA256\n"); | ||
|
||
SecurityTools.jarsigner("-verify signeda.jar " + | ||
"-J-Djava.security.properties=" + | ||
JAVA_SECURITY_FILE + | ||
" -keystore ks -storepass changeit -verbose -debug") | ||
.shouldMatch("Digest algorithm: SHA-256.*(weak)") | ||
.shouldMatch("Signature algorithm: PSSParameterSpec.*hashAlgorithm=SHA-256.*(weak)") | ||
.shouldNotContain("The jar will be treated as unsigned") | ||
.shouldHaveExitValue(0); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this import, as this class does not seem to be referenced anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed. Thanks for the review.