Skip to content

Commit 80380d5

Browse files
committed
8255494: PKCS7 should use digest algorithm to verify the signature
Reviewed-by: valeriep
1 parent 9d5c9cc commit 80380d5

File tree

3 files changed

+124
-13
lines changed

3 files changed

+124
-13
lines changed

src/java.base/share/classes/sun/security/pkcs/SignerInfo.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,6 @@ public void derEncode(OutputStream out) throws IOException {
260260
out.write(tmp.toByteArray());
261261
}
262262

263-
264-
265263
/*
266264
* Returns the (user) certificate pertaining to this SignerInfo.
267265
*/
@@ -503,24 +501,27 @@ SignerInfo verify(PKCS7 block, byte[] data)
503501

504502
/**
505503
* Derives the signature algorithm name from the digest algorithm
506-
* name and the encryption algorithm name inside a PKCS7 SignerInfo.
504+
* and the encryption algorithm inside a PKCS7 SignerInfo.
505+
*
506+
* The digest algorithm is in the form "DIG", and the encryption
507+
* algorithm can be in any of the 3 forms:
507508
*
508-
* For old style PKCS7 files where we use RSA, DSA, EC as encAlgId
509-
* a DIGESTwithENC algorithm is returned. For new style RSASSA-PSS
510-
* and EdDSA encryption, this method ensures digAlgId is compatible
511-
* with the algorithm.
509+
* 1. Old style key algorithm like RSA, DSA, EC, this method returns
510+
* DIGwithKEY.
511+
* 2. New style signature algorithm in the form of HASHwithKEY, this
512+
* method returns DIGwithKEY. Please note this is not HASHwithKEY.
513+
* 3. Modern signature algorithm like RSASSA-PSS and EdDSA, this method
514+
* returns the signature algorithm itself but ensures digAlgId is
515+
* compatible with the algorithm as described in RFC 4056 and 8419.
512516
*
513517
* @param digAlgId the digest algorithm
514-
* @param encAlgId the encryption or signature algorithm
518+
* @param encAlgId the encryption algorithm
515519
* @param directSign whether the signature is calculated on the content
516520
* directly. This makes difference for Ed448.
517521
*/
518522
public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId,
519523
boolean directSign) throws NoSuchAlgorithmException {
520524
String encAlg = encAlgId.getName();
521-
if (encAlg.contains("with")) {
522-
return encAlg;
523-
}
524525
switch (encAlg) {
525526
case "RSASSA-PSS":
526527
PSSParameterSpec spec = (PSSParameterSpec)
@@ -547,11 +548,16 @@ public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId,
547548
return encAlg;
548549
default:
549550
String digAlg = digAlgId.getName();
551+
String keyAlg = SignatureUtil.extractKeyAlgFromDwithE(encAlg);
552+
if (keyAlg == null) {
553+
// The encAlg used to be only the key alg
554+
keyAlg = encAlg;
555+
}
550556
if (digAlg.startsWith("SHA-")) {
551557
digAlg = "SHA" + digAlg.substring(4);
552558
}
553-
if (encAlg.equals("EC")) encAlg = "ECDSA";
554-
return digAlg + "with" + encAlg;
559+
if (keyAlg.equals("EC")) keyAlg = "ECDSA";
560+
return digAlg + "with" + keyAlg;
555561
}
556562
}
557563

src/java.base/share/classes/sun/security/util/SignatureUtil.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,32 @@ public static String extractDigestAlgFromDwithE(String signatureAlgorithm) {
282282
}
283283
}
284284

285+
/**
286+
* Extracts the key algorithm name from a signature
287+
* algorithm name in either the "DIGESTwithENCRYPTION" or the
288+
* "DIGESTwithENCRYPTIONandWHATEVER" format.
289+
*
290+
* @return the key algorithm name, or null if the input
291+
* is not in either of the formats.
292+
*/
293+
public static String extractKeyAlgFromDwithE(String signatureAlgorithm) {
294+
signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH);
295+
int with = signatureAlgorithm.indexOf("WITH");
296+
String keyAlgorithm = null;
297+
if (with > 0) {
298+
int and = signatureAlgorithm.indexOf("AND", with + 4);
299+
if (and > 0) {
300+
keyAlgorithm = signatureAlgorithm.substring(with + 4, and);
301+
} else {
302+
keyAlgorithm = signatureAlgorithm.substring(with + 4);
303+
}
304+
if (keyAlgorithm.equalsIgnoreCase("ECDSA")) {
305+
keyAlgorithm = "EC";
306+
}
307+
}
308+
return keyAlgorithm;
309+
}
310+
285311
/**
286312
* Returns default AlgorithmParameterSpec for a key used in a signature.
287313
* This is only useful for RSASSA-PSS now, which is the only algorithm
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8255494
27+
* @summary Make sure the signature algorithm to verify a PKCS7 block is
28+
* DIGwithENC instead of HASHwithENC.
29+
* @modules java.base/sun.security.pkcs
30+
* java.base/sun.security.tools.keytool
31+
* java.base/sun.security.x509
32+
*/
33+
34+
import sun.security.pkcs.PKCS7;
35+
import sun.security.tools.keytool.CertAndKeyGen;
36+
import sun.security.x509.X500Name;
37+
38+
import java.nio.charset.StandardCharsets;
39+
import java.security.cert.X509Certificate;
40+
41+
public class TwoHash {
42+
public static void main(String[] args) throws Exception {
43+
44+
byte[] content = "Hello You fool I love you".getBytes();
45+
46+
CertAndKeyGen cak = new CertAndKeyGen("EC", "SHA512withECDSA");
47+
cak.generate("secp256r1");
48+
byte[] signature = PKCS7.generateNewSignedData(
49+
"SHA256withECDSA",
50+
null,
51+
cak.getPrivateKey(),
52+
new X509Certificate[] {cak.getSelfCertificate(new X500Name("CN=Me"), 1000)},
53+
content,
54+
false,
55+
true, // direct sign, so that RFC 6211 check is not possible
56+
null);
57+
58+
// The original signature should verify.
59+
if (new PKCS7(signature).verify(content) == null) {
60+
throw new RuntimeException("Should be verified");
61+
}
62+
63+
// Modify the SHA256withECDSA signature algorithm (OID encoded as
64+
// "06 08 2A 86 48 CE 3D 04 03 02") to SHA384withECDSA (OID encoded as
65+
// "06 08 2A 86 48 CE 3D 04 03 03"). ISO_8859_1 charset is chosen
66+
// because it's a strictly one byte per char encoding.
67+
String s = new String(signature, StandardCharsets.ISO_8859_1);
68+
String s1 = s.replace(
69+
"\u0006\u0008\u002A\u0086\u0048\u00CE\u003D\u0004\u0003\u0002",
70+
"\u0006\u0008\u002A\u0086\u0048\u00CE\u003D\u0004\u0003\u0003");
71+
byte[] modified = s1.getBytes(StandardCharsets.ISO_8859_1);
72+
73+
// The modified signature should still verify because the HASH
74+
// part of signature algorithm is ignored.
75+
if (new PKCS7(modified).verify(content) == null) {
76+
throw new RuntimeException("Should be verified");
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)