Path: blob/master/test/jdk/java/security/cert/CertPathValidator/OCSP/GetAndPostTests.java
41161 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 817950326* @summary Java should support GET OCSP calls27* @library /javax/net/ssl/templates /java/security/testlibrary28* @build SimpleOCSPServer29* @modules java.base/sun.security.util30* java.base/sun.security.provider.certpath31* java.base/sun.security.x50932* @run main/othervm GetAndPostTests33*/3435import java.io.ByteArrayInputStream;36import java.io.IOException;37import java.io.OutputStream;38import java.net.URI;39import java.security.GeneralSecurityException;40import java.security.KeyFactory;41import java.security.KeyStore;42import java.security.PrivateKey;43import java.security.SecureRandom;44import java.security.cert.CertPath;45import java.security.cert.CertPathValidator;46import java.security.cert.Certificate;47import java.security.cert.CertificateException;48import java.security.cert.CertificateFactory;49import java.security.cert.Extension;50import java.security.cert.PKIXCertPathChecker;51import java.security.cert.PKIXParameters;52import java.security.cert.PKIXRevocationChecker;53import java.security.cert.TrustAnchor;54import java.security.cert.X509Certificate;55import java.security.spec.PKCS8EncodedKeySpec;56import java.util.Base64;57import java.util.Date;58import java.util.List;59import java.util.Map;60import java.util.Objects;61import java.util.Set;62import sun.security.testlibrary.SimpleOCSPServer;63import sun.security.testlibrary.SimpleOCSPServer;64import sun.security.testlibrary.SimpleOCSPServer;65import sun.security.util.DerOutputStream;66import sun.security.util.DerValue;67import sun.security.util.ObjectIdentifier;68import sun.security.testlibrary.SimpleOCSPServer;6970public class GetAndPostTests {71private static final String PASS = "passphrase";72private static CertificateFactory certFac;7374public static void main(String args[]) throws Exception {75SimpleOCSPServer ocspResponder = null;7677try {78certFac = CertificateFactory.getInstance("X.509");7980// Read in the certificates and keys needed for this test and81// create the keystore for the SimpleOCSPServer. For the purposes82// of this test, the CA certificate will also be the OCSP responder83// signing certificate.84SSLSocketTemplate.Cert certAuth =85SSLSocketTemplate.Cert.CA_ECDSA_SECP256R1;86X509Certificate caCert = pem2Cert(certAuth.certStr);87PrivateKey caKey = pem2Key(certAuth.privKeyStr, certAuth.keyAlgo);88X509Certificate endEntCert =89pem2Cert(SSLSocketTemplate.Cert.EE_ECDSA_SECP256R1.certStr);9091KeyStore.Builder keyStoreBuilder =92KeyStore.Builder.newInstance("PKCS12", null,93new KeyStore.PasswordProtection(PASS.toCharArray()));94KeyStore ocspStore = keyStoreBuilder.getKeyStore();95Certificate[] ocspChain = {caCert};96ocspStore.setKeyEntry("ocspsigner", caKey, PASS.toCharArray(),97ocspChain);9899// Create the certificate path we'll use for cert path validation.100CertPath path = certFac.generateCertPath(List.of(endEntCert));101102// Next, create and start the OCSP responder. Obtain the socket103// address so we can set that in the PKIXRevocationChecker since104// these certificates do not have AIA extensions on them.105ocspResponder = new SimpleOCSPServer(ocspStore, PASS,106"ocspsigner", null);107ocspResponder.setSignatureAlgorithm("SHA256WithECDSA");108ocspResponder.enableLog(true);109ocspResponder.setNextUpdateInterval(3600);110ocspResponder.updateStatusDb(Map.of(111endEntCert.getSerialNumber(),112new SimpleOCSPServer.CertStatusInfo(113SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)));114ocspResponder.start();115// Wait 5 seconds for server ready116for (int i = 0; (i < 100 && !ocspResponder.isServerReady()); i++) {117Thread.sleep(50);118}119if (!ocspResponder.isServerReady()) {120throw new RuntimeException("Server not ready yet");121}122123int ocspPort = ocspResponder.getPort();124URI ocspURI = new URI("http://localhost:" + ocspPort);125System.out.println("Configured CPV to connect to " + ocspURI);126127// Create the PKIXParameters needed for path validation and128// configure any necessary OCSP parameters to control the OCSP129// request size.130Set<TrustAnchor> anchors = Set.of(new TrustAnchor(caCert, null));131132CertPathValidator validator = CertPathValidator.getInstance("PKIX");133PKIXRevocationChecker revChkr =134(PKIXRevocationChecker)validator.getRevocationChecker();135revChkr.setOcspResponder(ocspURI);136revChkr.setOptions(Set.of(137PKIXRevocationChecker.Option.ONLY_END_ENTITY,138PKIXRevocationChecker.Option.NO_FALLBACK));139140PKIXParameters params = new PKIXParameters(anchors);141params.setRevocationEnabled(true);142params.setDate(new Date(1590926400000L)); // 05/31/2020 @ 12:00:00Z143params.addCertPathChecker(revChkr);144145System.out.println("Test 1: Request < 255 bytes, HTTP GET");146validator.validate(path, params);147148System.out.println("Test 2: Request > 255 bytes, HTTP POST");149// Modify the PKIXRevocationChecker to include a bogus non-critical150// request extension that makes the request large enough to be151// issued as an HTTP POST.152List<PKIXCertPathChecker> chkrList = params.getCertPathCheckers();153for (PKIXCertPathChecker chkr : chkrList) {154if (chkr instanceof PKIXRevocationChecker) {155((PKIXRevocationChecker)chkr).setOcspExtensions(156List.of(new BogusExtension("1.2.3.4.5.6.7.8.9",157false, 256)));158}159}160params.setCertPathCheckers(chkrList);161validator.validate(path, params);162163} finally {164if (ocspResponder != null) {165ocspResponder.stop();166}167}168}169170/**171* Create an X509Certificate object from its PEM encoding172*173* @param pemCert the base64 encoded certificate174*175* @return the corresponding X509Certificate object from the PEM encoding.176*177* @throws IOException if any InputStream or Base64 decoding failures occur.178* @throws CertificateException if any certificate parsing errors occur.179*/180private static X509Certificate pem2Cert(String pemCert)181throws IOException, CertificateException {182return (X509Certificate)certFac.generateCertificate(183new ByteArrayInputStream(pemCert.getBytes()));184}185186/**187* Create a private key from its PEM-encoded PKCS#8 representation.188*189* @param pemKey the private key in PEM-encoded PKCS#8 unencrypted format190* @param algorithm the private key algorithm191*192* @return the PrivateKey extracted from the PKCS#8 encoding.193*194* @throws GeneralSecurityException if any errors take place during195* decoding or parsing.196*/197private static PrivateKey pem2Key(String pemKey, String algorithm)198throws GeneralSecurityException {199byte[] p8Der = Base64.getMimeDecoder().decode(pemKey);200PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(p8Der, algorithm);201KeyFactory kf = KeyFactory.getInstance(algorithm);202return kf.generatePrivate(spec);203}204205/**206* The BogusOcspExtension is an extension with random data in the207* extension value field. It is used in this test to expand the size208* of the OCSP request so it crosses the boundary that forces an HTTP209* POST operation instead of a GET.210*/211private static class BogusExtension implements Extension {212private final ObjectIdentifier oid;213private final boolean critical;214private final byte[] data;215216public BogusExtension(String oidStr, boolean isCrit, int size)217throws IOException {218// For this test we don't need anything larger than 10K219if (size > 0 && size <= 10240) {220data = new byte[size];221} else {222throw new IllegalArgumentException(223"Size must be 0 < X <= 10240");224}225oid = ObjectIdentifier.of(oidStr);226SecureRandom sr = new SecureRandom();227sr.nextBytes(data);228critical = isCrit;229}230231@Override232public String getId() {233return oid.toString();234}235236@Override237public boolean isCritical() {238return critical;239}240241@Override242public byte[] getValue() {243return data.clone();244}245246@Override247public void encode(OutputStream out) throws IOException {248Objects.requireNonNull(out, "Non-null OutputStream required");249250DerOutputStream dos1 = new DerOutputStream();251DerOutputStream dos2 = new DerOutputStream();252253dos1.putOID(oid);254if (critical) {255dos1.putBoolean(critical);256}257dos1.putOctetString(data);258259dos2.write(DerValue.tag_Sequence, dos1);260out.write(dos2.toByteArray());261}262}263}264265266