8274471: Verification of OCSP Response signed with RSASSA-PSS fails

Reviewed-by: hchao, jnimeh
This commit is contained in:
Weijun Wang 2021-10-04 15:30:44 +00:00
parent f2404d60de
commit f63c4a832a
9 changed files with 65 additions and 86 deletions

View file

@ -35,7 +35,6 @@ import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CRLReason; import java.security.cert.CRLReason;
import java.security.cert.Extension; import java.security.cert.Extension;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Base64; import java.util.Base64;
import java.util.Date; import java.util.Date;
@ -46,7 +45,6 @@ import sun.security.action.GetIntegerAction;
import sun.security.util.Debug; import sun.security.util.Debug;
import sun.security.util.Event; import sun.security.util.Event;
import sun.security.util.IOUtils; import sun.security.util.IOUtils;
import sun.security.validator.Validator;
import sun.security.x509.AccessDescription; import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.GeneralName; import sun.security.x509.GeneralName;
@ -166,22 +164,26 @@ public final class OCSP {
List<Extension> extensions) throws IOException { List<Extension> extensions) throws IOException {
OCSPRequest request = new OCSPRequest(certIds, extensions); OCSPRequest request = new OCSPRequest(certIds, extensions);
byte[] bytes = request.encodeBytes(); byte[] bytes = request.encodeBytes();
String responder = responderURI.toString();
if (debug != null) { if (debug != null) {
debug.println("connecting to OCSP service at: " + responderURI); debug.println("connecting to OCSP service at: " + responder);
} }
Event.report(Event.ReporterCategory.CRLCHECK, "event.ocsp.check", Event.report(Event.ReporterCategory.CRLCHECK, "event.ocsp.check",
responderURI.toString()); responder);
URL url; URL url;
HttpURLConnection con = null; HttpURLConnection con = null;
try { try {
String encodedGetReq = responderURI.toString() + "/" + StringBuilder encodedGetReq = new StringBuilder(responder);
URLEncoder.encode(Base64.getEncoder().encodeToString(bytes), if (!responder.endsWith("/")) {
UTF_8); encodedGetReq.append("/");
}
encodedGetReq.append(URLEncoder.encode(
Base64.getEncoder().encodeToString(bytes), UTF_8));
if (encodedGetReq.length() <= 255) { if (encodedGetReq.length() <= 255) {
url = new URL(encodedGetReq); url = new URL(encodedGetReq.toString());
con = (HttpURLConnection)url.openConnection(); con = (HttpURLConnection)url.openConnection();
con.setDoOutput(true); con.setDoOutput(true);
con.setDoInput(true); con.setDoInput(true);

View file

@ -638,7 +638,10 @@ public final class OCSPResponse {
try { try {
Signature respSignature = Signature.getInstance(sigAlgId.getName()); Signature respSignature = Signature.getInstance(sigAlgId.getName());
respSignature.initVerify(cert.getPublicKey()); SignatureUtil.initVerifyWithParam(respSignature,
cert.getPublicKey(),
SignatureUtil.getParamSpec(sigAlgId.getName(),
sigAlgId.getEncodedParams()));
respSignature.update(tbsResponseData); respSignature.update(tbsResponseData);
if (respSignature.verify(signature)) { if (respSignature.verify(signature)) {
@ -654,8 +657,8 @@ public final class OCSPResponse {
} }
return false; return false;
} }
} catch (InvalidKeyException | NoSuchAlgorithmException | } catch (InvalidAlgorithmParameterException | InvalidKeyException
SignatureException e) | NoSuchAlgorithmException | SignatureException e)
{ {
throw new CertPathValidatorException(e); throw new CertPathValidatorException(e);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -170,8 +170,7 @@ public class SignatureUtil {
// for verification with the specified key and params (may be null) // for verification with the specified key and params (may be null)
public static void initVerifyWithParam(Signature s, PublicKey key, public static void initVerifyWithParam(Signature s, PublicKey key,
AlgorithmParameterSpec params) AlgorithmParameterSpec params)
throws ProviderException, InvalidAlgorithmParameterException, throws InvalidAlgorithmParameterException, InvalidKeyException {
InvalidKeyException {
SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params); SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params);
} }
@ -180,8 +179,7 @@ public class SignatureUtil {
public static void initVerifyWithParam(Signature s, public static void initVerifyWithParam(Signature s,
java.security.cert.Certificate cert, java.security.cert.Certificate cert,
AlgorithmParameterSpec params) AlgorithmParameterSpec params)
throws ProviderException, InvalidAlgorithmParameterException, throws InvalidAlgorithmParameterException, InvalidKeyException {
InvalidKeyException {
SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params); SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params);
} }
@ -189,8 +187,7 @@ public class SignatureUtil {
// for signing with the specified key and params (may be null) // for signing with the specified key and params (may be null)
public static void initSignWithParam(Signature s, PrivateKey key, public static void initSignWithParam(Signature s, PrivateKey key,
AlgorithmParameterSpec params, SecureRandom sr) AlgorithmParameterSpec params, SecureRandom sr)
throws ProviderException, InvalidAlgorithmParameterException, throws InvalidAlgorithmParameterException, InvalidKeyException {
InvalidKeyException {
SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr); SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr);
} }
@ -342,10 +339,10 @@ public class SignatureUtil {
* Create a Signature that has been initialized with proper key and params. * Create a Signature that has been initialized with proper key and params.
* *
* @param sigAlg signature algorithms * @param sigAlg signature algorithms
* @param key public or private key * @param key private key
* @param provider (optional) provider * @param provider (optional) provider
*/ */
public static Signature fromKey(String sigAlg, Key key, String provider) public static Signature fromKey(String sigAlg, PrivateKey key, String provider)
throws NoSuchAlgorithmException, NoSuchProviderException, throws NoSuchAlgorithmException, NoSuchProviderException,
InvalidKeyException{ InvalidKeyException{
Signature sigEngine = (provider == null || provider.isEmpty()) Signature sigEngine = (provider == null || provider.isEmpty())
@ -358,10 +355,10 @@ public class SignatureUtil {
* Create a Signature that has been initialized with proper key and params. * Create a Signature that has been initialized with proper key and params.
* *
* @param sigAlg signature algorithms * @param sigAlg signature algorithms
* @param key public or private key * @param key private key
* @param provider (optional) provider * @param provider (optional) provider
*/ */
public static Signature fromKey(String sigAlg, Key key, Provider provider) public static Signature fromKey(String sigAlg, PrivateKey key, Provider provider)
throws NoSuchAlgorithmException, InvalidKeyException{ throws NoSuchAlgorithmException, InvalidKeyException{
Signature sigEngine = (provider == null) Signature sigEngine = (provider == null)
? Signature.getInstance(sigAlg) ? Signature.getInstance(sigAlg)
@ -369,17 +366,12 @@ public class SignatureUtil {
return autoInitInternal(sigAlg, key, sigEngine); return autoInitInternal(sigAlg, key, sigEngine);
} }
private static Signature autoInitInternal(String alg, Key key, Signature s) private static Signature autoInitInternal(String alg, PrivateKey key, Signature s)
throws InvalidKeyException { throws InvalidKeyException {
AlgorithmParameterSpec params = SignatureUtil AlgorithmParameterSpec params = SignatureUtil
.getDefaultParamSpec(alg, key); .getDefaultParamSpec(alg, key);
try { try {
if (key instanceof PrivateKey) { SignatureUtil.initSignWithParam(s, key, params, null);
SignatureUtil.initSignWithParam(s, (PrivateKey) key, params,
null);
} else {
SignatureUtil.initVerifyWithParam(s, (PublicKey) key, params);
}
} catch (InvalidAlgorithmParameterException e) { } catch (InvalidAlgorithmParameterException e) {
throw new AssertionError("Should not happen", e); throw new AssertionError("Should not happen", e);
} }

View file

@ -312,7 +312,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
* *
* @return DER encoded parameters, or null not present. * @return DER encoded parameters, or null not present.
*/ */
public byte[] getEncodedParams() throws IOException { public byte[] getEncodedParams() {
return (encodedParams == null || return (encodedParams == null ||
algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value())) algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value()))
? null ? null

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -820,13 +820,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder {
* null if no parameters are present. * null if no parameters are present.
*/ */
public byte[] getSigAlgParams() { public byte[] getSigAlgParams() {
if (sigAlgId == null) return sigAlgId == null ? null : sigAlgId.getEncodedParams();
return null;
try {
return sigAlgId.getEncodedParams();
} catch (IOException e) {
return null;
}
} }
/** /**

View file

@ -1030,13 +1030,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
* null if no parameters are present. * null if no parameters are present.
*/ */
public byte[] getSigAlgParams() { public byte[] getSigAlgParams() {
if (algId == null) return algId == null ? null : algId.getEncodedParams();
return null;
try {
return algId.getEncodedParams();
} catch (IOException e) {
return null;
}
} }
/** /**

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,7 @@ import java.math.BigInteger;
import sun.security.util.DerOutputStream; import sun.security.util.DerOutputStream;
import sun.security.util.DerValue; import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier; import sun.security.util.ObjectIdentifier;
import sun.security.util.SignatureUtil;
import sun.security.x509.AccessDescription; import sun.security.x509.AccessDescription;
import sun.security.x509.AlgorithmId; import sun.security.x509.AlgorithmId;
import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.AuthorityInfoAccessExtension;
@ -364,8 +365,7 @@ public class CertificateBuilder {
throws IOException, CertificateException, NoSuchAlgorithmException { throws IOException, CertificateException, NoSuchAlgorithmException {
// TODO: add some basic checks (key usage, basic constraints maybe) // TODO: add some basic checks (key usage, basic constraints maybe)
AlgorithmId signAlg = AlgorithmId.get(algName); byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName);
byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg);
ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert);
return (X509Certificate)factory.generateCertificate(bais); return (X509Certificate)factory.generateCertificate(bais);
} }
@ -392,18 +392,24 @@ public class CertificateBuilder {
* @throws IOException if an encoding error occurs. * @throws IOException if an encoding error occurs.
*/ */
private byte[] encodeTopLevel(X509Certificate issuerCert, private byte[] encodeTopLevel(X509Certificate issuerCert,
PrivateKey issuerKey, AlgorithmId signAlg) PrivateKey issuerKey, String algName)
throws CertificateException, IOException { throws CertificateException, IOException, NoSuchAlgorithmException {
AlgorithmId signAlg = AlgorithmId.get(algName);
DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream outerSeq = new DerOutputStream();
DerOutputStream topLevelItems = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream();
tbsCertBytes = encodeTbsCert(issuerCert, signAlg);
topLevelItems.write(tbsCertBytes);
try { try {
signatureBytes = signCert(issuerKey, signAlg); Signature sig = SignatureUtil.fromKey(signAlg.getName(), issuerKey, (Provider)null);
// Rewrite signAlg, RSASSA-PSS needs some parameters.
signAlg = SignatureUtil.fromSignature(sig, issuerKey);
tbsCertBytes = encodeTbsCert(issuerCert, signAlg);
sig.update(tbsCertBytes);
signatureBytes = sig.sign();
} catch (GeneralSecurityException ge) { } catch (GeneralSecurityException ge) {
throw new CertificateException(ge); throw new CertificateException(ge);
} }
topLevelItems.write(tbsCertBytes);
signAlg.derEncode(topLevelItems); signAlg.derEncode(topLevelItems);
topLevelItems.putBitString(signatureBytes); topLevelItems.putBitString(signatureBytes);
outerSeq.write(DerValue.tag_Sequence, topLevelItems); outerSeq.write(DerValue.tag_Sequence, topLevelItems);
@ -518,22 +524,4 @@ public class CertificateBuilder {
(byte)3), extSequence); (byte)3), extSequence);
} }
/** }
* Digitally sign the X.509 certificate.
*
* @param issuerKey The private key of the issuing authority
* @param signAlg The signature algorithm object
*
* @return The digital signature bytes.
*
* @throws GeneralSecurityException If any errors occur during the
* digital signature process.
*/
private byte[] signCert(PrivateKey issuerKey, AlgorithmId signAlg)
throws GeneralSecurityException {
Signature sig = Signature.getInstance(signAlg.getName());
sig.initSign(issuerKey);
sig.update(tbsCertBytes);
return sig.sign();
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -174,8 +174,7 @@ public class SimpleOCSPServer {
issuerAlias + " not found"); issuerAlias + " not found");
} }
} }
sigAlgId = AlgorithmId.get(SignatureUtil.getDefaultSigAlgForKey(signerKey));
sigAlgId = AlgorithmId.get("Sha256withRSA");
respId = new ResponderId(signerCert.getSubjectX500Principal()); respId = new ResponderId(signerCert.getSubjectX500Principal());
listenAddress = addr; listenAddress = addr;
listenPort = port; listenPort = port;
@ -1348,13 +1347,14 @@ public class SimpleOCSPServer {
basicORItemStream.write(tbsResponseBytes); basicORItemStream.write(tbsResponseBytes);
try { try {
sigAlgId.derEncode(basicORItemStream);
// Create the signature // Create the signature
Signature sig = Signature.getInstance(sigAlgId.getName()); Signature sig = SignatureUtil.fromKey(
sig.initSign(signerKey); sigAlgId.getName(), signerKey, (Provider)null);
sig.update(tbsResponseBytes); sig.update(tbsResponseBytes);
signature = sig.sign(); signature = sig.sign();
// Rewrite signAlg, RSASSA-PSS needs some parameters.
sigAlgId = SignatureUtil.fromSignature(sig, signerKey);
sigAlgId.derEncode(basicORItemStream);
basicORItemStream.putBitString(signature); basicORItemStream.putBitString(signature);
} catch (GeneralSecurityException exc) { } catch (GeneralSecurityException exc) {
err(exc); err(exc);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,7 +30,8 @@
* @summary OCSP Stapling for TLS * @summary OCSP Stapling for TLS
* @library ../../../../java/security/testlibrary * @library ../../../../java/security/testlibrary
* @build CertificateBuilder SimpleOCSPServer * @build CertificateBuilder SimpleOCSPServer
* @run main/othervm HttpsUrlConnClient * @run main/othervm HttpsUrlConnClient RSA SHA256withRSA
* @run main/othervm HttpsUrlConnClient RSASSA-PSS RSASSA-PSS
*/ */
import java.io.*; import java.io.*;
@ -60,7 +61,6 @@ import java.util.concurrent.TimeUnit;
import sun.security.testlibrary.SimpleOCSPServer; import sun.security.testlibrary.SimpleOCSPServer;
import sun.security.testlibrary.CertificateBuilder; import sun.security.testlibrary.CertificateBuilder;
import sun.security.validator.ValidatorException;
public class HttpsUrlConnClient { public class HttpsUrlConnClient {
@ -73,6 +73,9 @@ public class HttpsUrlConnClient {
static final byte[] LINESEP = { 10 }; static final byte[] LINESEP = { 10 };
static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP); static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP);
static String SIGALG;
static String KEYALG;
// Turn on TLS debugging // Turn on TLS debugging
static boolean debug = true; static boolean debug = true;
@ -137,6 +140,9 @@ public class HttpsUrlConnClient {
System.setProperty("javax.net.ssl.trustStore", ""); System.setProperty("javax.net.ssl.trustStore", "");
System.setProperty("javax.net.ssl.trustStorePassword", ""); System.setProperty("javax.net.ssl.trustStorePassword", "");
KEYALG = args[0];
SIGALG = args[1];
// Create the PKI we will use for the test and start the OCSP servers // Create the PKI we will use for the test and start the OCSP servers
createPKI(); createPKI();
utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
@ -514,7 +520,7 @@ public class HttpsUrlConnClient {
*/ */
private static void createPKI() throws Exception { private static void createPKI() throws Exception {
CertificateBuilder cbld = new CertificateBuilder(); CertificateBuilder cbld = new CertificateBuilder();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEYALG);
keyGen.initialize(2048); keyGen.initialize(2048);
KeyStore.Builder keyStoreBuilder = KeyStore.Builder keyStoreBuilder =
KeyStore.Builder.newInstance("PKCS12", null, KeyStore.Builder.newInstance("PKCS12", null,
@ -540,7 +546,7 @@ public class HttpsUrlConnClient {
addCommonCAExts(cbld); addCommonCAExts(cbld);
// Make our Root CA Cert! // Make our Root CA Cert!
X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
"SHA256withRSA"); SIGALG);
log("Root CA Created:\n" + certInfo(rootCert)); log("Root CA Created:\n" + certInfo(rootCert));
// Now build a keystore and add the keys and cert // Now build a keystore and add the keys and cert
@ -582,7 +588,7 @@ public class HttpsUrlConnClient {
cbld.addAIAExt(Collections.singletonList(rootRespURI)); cbld.addAIAExt(Collections.singletonList(rootRespURI));
// Make our Intermediate CA Cert! // Make our Intermediate CA Cert!
X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
"SHA256withRSA"); SIGALG);
log("Intermediate CA Created:\n" + certInfo(intCaCert)); log("Intermediate CA Created:\n" + certInfo(intCaCert));
// Provide intermediate CA cert revocation info to the Root CA // Provide intermediate CA cert revocation info to the Root CA
@ -644,7 +650,7 @@ public class HttpsUrlConnClient {
cbld.addAIAExt(Collections.singletonList(intCaRespURI)); cbld.addAIAExt(Collections.singletonList(intCaRespURI));
// Make our SSL Server Cert! // Make our SSL Server Cert!
X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
"SHA256withRSA"); SIGALG);
log("SSL Certificate Created:\n" + certInfo(sslCert)); log("SSL Certificate Created:\n" + certInfo(sslCert));
// Provide SSL server cert revocation info to the Intermeidate CA // Provide SSL server cert revocation info to the Intermeidate CA