diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java index 699c15fe8ad..6cab0d9f53e 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java @@ -225,20 +225,24 @@ public static byte[] getOCSPBytes(List certIds, URI responderURI, List extensions) throws IOException { OCSPRequest request = new OCSPRequest(certIds, extensions); byte[] bytes = request.encodeBytes(); + String responder = responderURI.toString(); if (debug != null) { - debug.println("connecting to OCSP service at: " + responderURI); + debug.println("connecting to OCSP service at: " + responder); } HttpURLConnection con = null; try { - String encodedGetReq = responderURI.toString() + "/" + - URLEncoder.encode(Base64.getEncoder().encodeToString(bytes), - "UTF-8"); + StringBuilder encodedGetReq = new StringBuilder(responder); + if (!responder.endsWith("/")) { + encodedGetReq.append("/"); + } + encodedGetReq.append(URLEncoder.encode( + Base64.getEncoder().encodeToString(bytes), "UTF-8")); if (encodedGetReq.length() <= 255) { - URL url = new URL(encodedGetReq); + URL url = new URL(encodedGetReq.toString()); con = (HttpURLConnection)url.openConnection(); con.setDoOutput(true); con.setDoInput(true); diff --git a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java index d6163673b50..562e697d525 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -639,7 +639,10 @@ private boolean verifySignature(X509Certificate cert) try { Signature respSignature = Signature.getInstance(sigAlgId.getName()); - respSignature.initVerify(cert.getPublicKey()); + SignatureUtil.initVerifyWithParam(respSignature, + cert.getPublicKey(), + SignatureUtil.getParamSpec(sigAlgId.getName(), + sigAlgId.getEncodedParams())); respSignature.update(tbsResponseData); if (respSignature.verify(signature)) { @@ -655,8 +658,8 @@ private boolean verifySignature(X509Certificate cert) } return false; } - } catch (InvalidKeyException | NoSuchAlgorithmException | - SignatureException e) + } catch (InvalidAlgorithmParameterException | InvalidKeyException + | NoSuchAlgorithmException | SignatureException e) { throw new CertPathValidatorException(e); } diff --git a/jdk/src/share/classes/sun/security/util/SignatureUtil.java b/jdk/src/share/classes/sun/security/util/SignatureUtil.java index 9516a62c7a9..72fa12d9aa1 100644 --- a/jdk/src/share/classes/sun/security/util/SignatureUtil.java +++ b/jdk/src/share/classes/sun/security/util/SignatureUtil.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.security.spec.*; import java.util.Locale; import sun.security.rsa.RSAUtil; +import sun.security.x509.AlgorithmId; import sun.misc.SharedSecrets; /** @@ -145,8 +146,7 @@ public static AlgorithmParameterSpec getParamSpec(String sigName, // for verification with the specified key and params (may be null) public static void initVerifyWithParam(Signature s, PublicKey key, AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params); } @@ -155,8 +155,7 @@ public static void initVerifyWithParam(Signature s, PublicKey key, public static void initVerifyWithParam(Signature s, java.security.cert.Certificate cert, AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params); } @@ -164,8 +163,83 @@ public static void initVerifyWithParam(Signature s, // for signing with the specified key and params (may be null) public static void initSignWithParam(Signature s, PrivateKey key, AlgorithmParameterSpec params, SecureRandom sr) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr); } + + /** + * Create a Signature that has been initialized with proper key and params. + * + * @param sigAlg signature algorithms + * @param key private key + * @param provider (optional) provider + */ + public static Signature fromKey(String sigAlg, PrivateKey key, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException, + InvalidKeyException{ + Signature sigEngine = (provider == null || provider.isEmpty()) + ? Signature.getInstance(sigAlg) + : Signature.getInstance(sigAlg, provider); + return autoInitInternal(sigAlg, key, sigEngine); + } + + /** + * Create a Signature that has been initialized with proper key and params. + * + * @param sigAlg signature algorithms + * @param key private key + * @param provider (optional) provider + */ + public static Signature fromKey(String sigAlg, PrivateKey key, Provider provider) + throws NoSuchAlgorithmException, InvalidKeyException{ + Signature sigEngine = (provider == null) + ? Signature.getInstance(sigAlg) + : Signature.getInstance(sigAlg, provider); + return autoInitInternal(sigAlg, key, sigEngine); + } + + private static Signature autoInitInternal(String alg, PrivateKey key, Signature s) + throws InvalidKeyException { + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(alg, key); + try { + SignatureUtil.initSignWithParam(s, key, params, null); + } catch (InvalidAlgorithmParameterException e) { + throw new AssertionError("Should not happen", e); + } + return s; + } + + /** + * Derives AlgorithmId from a signature object and a key. + * @param sigEngine the signature object + * @param key the private key + * @return the AlgorithmId, not null + * @throws SignatureException if cannot find one + */ + public static AlgorithmId fromSignature(Signature sigEngine, PrivateKey key) + throws SignatureException { + try { + AlgorithmParameters params = null; + try { + params = sigEngine.getParameters(); + } catch (UnsupportedOperationException e) { + // some provider does not support it + } + if (params != null) { + return AlgorithmId.get(sigEngine.getParameters()); + } else { + String sigAlg = sigEngine.getAlgorithm(); + if (sigAlg.equalsIgnoreCase("EdDSA")) { + // Hopefully key knows if it's Ed25519 or Ed448 + sigAlg = key.getAlgorithm(); + } + return AlgorithmId.get(sigAlg); + } + } catch (NoSuchAlgorithmException e) { + // This could happen if both sig alg and key alg is EdDSA, + // we don't know which provider does this. + throw new SignatureException("Cannot derive AlgorithmIdentifier", e); + } + } } diff --git a/jdk/src/share/classes/sun/security/x509/AlgorithmId.java b/jdk/src/share/classes/sun/security/x509/AlgorithmId.java index c7c7f16ba50..8efdc7208c3 100644 --- a/jdk/src/share/classes/sun/security/x509/AlgorithmId.java +++ b/jdk/src/share/classes/sun/security/x509/AlgorithmId.java @@ -291,7 +291,7 @@ public AlgorithmParameters getParameters() { * * @return DER encoded parameters, or null not present. */ - public byte[] getEncodedParams() throws IOException { + public byte[] getEncodedParams() { return (encodedParams == null || algid.equals(specifiedWithECDSA_oid)) ? null : encodedParams.clone(); @@ -1070,6 +1070,33 @@ public static String getDigAlgFromSigAlg(String signatureAlgorithm) { return null; } + /** + * Returns the default signature algorithm for a private key. The digest + * part might evolve with time. Remember to update the spec of + * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm(PrivateKey)} + * if updated. + * + * @param k cannot be null + * @return the default alg, might be null if unsupported + */ + public static String getDefaultSigAlgForKey(PrivateKey k) { + switch (k.getAlgorithm().toUpperCase(Locale.ENGLISH)) { + case "EC": + return ecStrength(KeyUtil.getKeySize(k)) + + "withECDSA"; + case "DSA": + return ifcFfcStrength(KeyUtil.getKeySize(k)) + + "withDSA"; + case "RSA": + return ifcFfcStrength(KeyUtil.getKeySize(k)) + + "withRSA"; + case "RSASSA-PSS": + return "RSASSA-PSS"; + default: + return null; + } + } + // Most commonly used PSSParameterSpec and AlgorithmId private static class PSSParamsHolder { @@ -1145,6 +1172,17 @@ public static PSSParameterSpec getDefaultAlgorithmParameterSpec( } } + // Values from SP800-57 part 1 rev 4 tables 2 and 3 + private static String ecStrength (int bitLength) { + if (bitLength >= 512) { // 256 bits of strength + return "SHA512"; + } else if (bitLength >= 384) { // 192 bits of strength + return "SHA384"; + } else { // 128 bits of strength and less + return "SHA256"; + } + } + // Same values for RSA and DSA (from 8056174) private static String ifcFfcStrength(int bitLength) { if (bitLength > 7680) { // 256 bits diff --git a/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java b/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java index c5decfa8d4a..f75908d200c 100644 --- a/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java +++ b/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -809,13 +809,7 @@ public String getSigAlgOID() { * null if no parameters are present. */ public byte[] getSigAlgParams() { - if (sigAlgId == null) - return null; - try { - return sigAlgId.getEncodedParams(); - } catch (IOException e) { - return null; - } + return sigAlgId == null ? null : sigAlgId.getEncodedParams(); } /** diff --git a/jdk/src/share/classes/sun/security/x509/X509CertImpl.java b/jdk/src/share/classes/sun/security/x509/X509CertImpl.java index 012bb8cf823..9f01e62dfff 100644 --- a/jdk/src/share/classes/sun/security/x509/X509CertImpl.java +++ b/jdk/src/share/classes/sun/security/x509/X509CertImpl.java @@ -1095,13 +1095,7 @@ public String getSigAlgOID() { * null if no parameters are present. */ public byte[] getSigAlgParams() { - if (algId == null) - return null; - try { - return algId.getEncodedParams(); - } catch (IOException e) { - return null; - } + return algId == null ? null : algId.getEncodedParams(); } /** diff --git a/jdk/test/java/security/testlibrary/CertificateBuilder.java b/jdk/test/java/security/testlibrary/CertificateBuilder.java index 4ab26d0d12e..f0a835b7c13 100644 --- a/jdk/test/java/security/testlibrary/CertificateBuilder.java +++ b/jdk/test/java/security/testlibrary/CertificateBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 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. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import sun.security.util.DerOutputStream; import sun.security.util.DerValue; import sun.security.util.ObjectIdentifier; +import sun.security.util.SignatureUtil; import sun.security.x509.AccessDescription; import sun.security.x509.AlgorithmId; import sun.security.x509.AuthorityInfoAccessExtension; @@ -364,8 +365,7 @@ public X509Certificate build(X509Certificate issuerCert, throws IOException, CertificateException, NoSuchAlgorithmException { // TODO: add some basic checks (key usage, basic constraints maybe) - AlgorithmId signAlg = AlgorithmId.get(algName); - byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg); + byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); return (X509Certificate)factory.generateCertificate(bais); } @@ -392,18 +392,24 @@ public X509Certificate build(X509Certificate issuerCert, * @throws IOException if an encoding error occurs. */ private byte[] encodeTopLevel(X509Certificate issuerCert, - PrivateKey issuerKey, AlgorithmId signAlg) - throws CertificateException, IOException { + PrivateKey issuerKey, String algName) + throws CertificateException, IOException, NoSuchAlgorithmException { + + AlgorithmId signAlg = AlgorithmId.get(algName); DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream(); - tbsCertBytes = encodeTbsCert(issuerCert, signAlg); - topLevelItems.write(tbsCertBytes); 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) { throw new CertificateException(ge); } + topLevelItems.write(tbsCertBytes); signAlg.derEncode(topLevelItems); topLevelItems.putBitString(signatureBytes); outerSeq.write(DerValue.tag_Sequence, topLevelItems); @@ -517,23 +523,4 @@ private void encodeExtensions(DerOutputStream tbsStream) tbsStream.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (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(); - } } diff --git a/jdk/test/java/security/testlibrary/SimpleOCSPServer.java b/jdk/test/java/security/testlibrary/SimpleOCSPServer.java index 1c6f05058f6..85b4d06694f 100644 --- a/jdk/test/java/security/testlibrary/SimpleOCSPServer.java +++ b/jdk/test/java/security/testlibrary/SimpleOCSPServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, 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. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,7 @@ import sun.security.util.DerOutputStream; import sun.security.util.DerValue; import sun.security.util.ObjectIdentifier; +import sun.security.util.SignatureUtil; /** @@ -179,7 +180,7 @@ public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks, } } - sigAlgId = AlgorithmId.get("Sha256withRSA"); + sigAlgId = AlgorithmId.get(AlgorithmId.getDefaultSigAlgForKey(signerKey)); respId = new ResponderId(signerCert.getSubjectX500Principal()); listenAddress = addr; listenPort = port; @@ -1352,13 +1353,14 @@ private byte[] encodeBasicOcspResponse() throws IOException { basicORItemStream.write(tbsResponseBytes); try { - sigAlgId.derEncode(basicORItemStream); - // Create the signature - Signature sig = Signature.getInstance(sigAlgId.getName()); - sig.initSign(signerKey); + Signature sig = SignatureUtil.fromKey( + sigAlgId.getName(), signerKey, (Provider)null); sig.update(tbsResponseBytes); signature = sig.sign(); + // Rewrite signAlg, RSASSA-PSS needs some parameters. + sigAlgId = SignatureUtil.fromSignature(sig, signerKey); + sigAlgId.derEncode(basicORItemStream); basicORItemStream.putBitString(signature); } catch (GeneralSecurityException exc) { err(exc); diff --git a/jdk/test/javax/net/ssl/Stapling/HttpsUrlConnClient.java b/jdk/test/javax/net/ssl/Stapling/HttpsUrlConnClient.java index 646182ec41d..8fedde9b985 100644 --- a/jdk/test/javax/net/ssl/Stapling/HttpsUrlConnClient.java +++ b/jdk/test/javax/net/ssl/Stapling/HttpsUrlConnClient.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,8 @@ * @summary OCSP Stapling for TLS * @library ../../../../java/security/testlibrary * @build CertificateBuilder SimpleOCSPServer - * @run main/othervm HttpsUrlConnClient + * @run main/othervm HttpsUrlConnClient RSA SHA256withRSA + * @run main/othervm HttpsUrlConnClient RSASSA-PSS RSASSA-PSS */ import java.io.*; @@ -60,7 +61,6 @@ import sun.security.testlibrary.SimpleOCSPServer; import sun.security.testlibrary.CertificateBuilder; -import sun.security.validator.ValidatorException; public class HttpsUrlConnClient { @@ -73,6 +73,9 @@ public class HttpsUrlConnClient { static final byte[] LINESEP = { 10 }; static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP); + static String SIGALG; + static String KEYALG; + // Turn on TLS debugging static boolean debug = true; @@ -137,6 +140,9 @@ public static void main(String[] args) throws Exception { System.setProperty("javax.net.ssl.trustStore", ""); 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 createPKI(); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); @@ -514,7 +520,7 @@ public void run() { */ private static void createPKI() throws Exception { CertificateBuilder cbld = new CertificateBuilder(); - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEYALG); keyGen.initialize(2048); KeyStore.Builder keyStoreBuilder = KeyStore.Builder.newInstance("PKCS12", null, @@ -540,7 +546,7 @@ private static void createPKI() throws Exception { addCommonCAExts(cbld); // Make our Root CA Cert! X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("Root CA Created:\n" + certInfo(rootCert)); // Now build a keystore and add the keys and cert @@ -582,7 +588,7 @@ private static void createPKI() throws Exception { cbld.addAIAExt(Collections.singletonList(rootRespURI)); // Make our Intermediate CA Cert! X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("Intermediate CA Created:\n" + certInfo(intCaCert)); // Provide intermediate CA cert revocation info to the Root CA @@ -644,7 +650,7 @@ private static void createPKI() throws Exception { cbld.addAIAExt(Collections.singletonList(intCaRespURI)); // Make our SSL Server Cert! X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("SSL Certificate Created:\n" + certInfo(sslCert)); // Provide SSL server cert revocation info to the Intermeidate CA