| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
package sun.security.provider.certpath;  | 
 | 
 | 
 | 
import java.io.InputStream;  | 
 | 
import java.io.IOException;  | 
 | 
import java.io.OutputStream;  | 
 | 
import java.net.URI;  | 
 | 
import java.net.URL;  | 
 | 
import java.net.HttpURLConnection;  | 
 | 
import java.security.cert.CertificateException;  | 
 | 
import java.security.cert.CertPathValidatorException;  | 
 | 
import java.security.cert.CertPathValidatorException.BasicReason;  | 
 | 
import java.security.cert.CRLReason;  | 
 | 
import java.security.cert.Extension;  | 
 | 
import java.security.cert.TrustAnchor;  | 
 | 
import java.security.cert.X509Certificate;  | 
 | 
import java.util.Arrays;  | 
 | 
import java.util.Collections;  | 
 | 
import java.util.Date;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Map;  | 
 | 
 | 
 | 
import sun.security.action.GetIntegerAction;  | 
 | 
import sun.security.util.Debug;  | 
 | 
import sun.security.validator.Validator;  | 
 | 
import sun.security.x509.AccessDescription;  | 
 | 
import sun.security.x509.AuthorityInfoAccessExtension;  | 
 | 
import sun.security.x509.GeneralName;  | 
 | 
import sun.security.x509.GeneralNameInterface;  | 
 | 
import sun.security.x509.PKIXExtensions;  | 
 | 
import sun.security.x509.URIName;  | 
 | 
import sun.security.x509.X509CertImpl;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public final class OCSP { | 
 | 
 | 
 | 
    private static final Debug debug = Debug.getInstance("certpath"); | 
 | 
 | 
 | 
    private static final int DEFAULT_CONNECT_TIMEOUT = 15000;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final int CONNECT_TIMEOUT = initializeTimeout();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static int initializeTimeout() { | 
 | 
        Integer tmp = java.security.AccessController.doPrivileged(  | 
 | 
                new GetIntegerAction("com.sun.security.ocsp.timeout")); | 
 | 
        if (tmp == null || tmp < 0) { | 
 | 
            return DEFAULT_CONNECT_TIMEOUT;  | 
 | 
        }  | 
 | 
        // Convert to milliseconds, as the system property will be  | 
 | 
          | 
 | 
        return tmp * 1000;  | 
 | 
    }  | 
 | 
 | 
 | 
    private OCSP() {} | 
 | 
 | 
 | 
 | 
 | 
    /**  | 
 | 
     * Obtains the revocation status of a certificate using OCSP.  | 
 | 
     *  | 
 | 
     * @param cert the certificate to be checked  | 
 | 
     * @param issuerCert the issuer certificate  | 
 | 
     * @param responderURI the URI of the OCSP responder  | 
 | 
     * @param responderCert the OCSP responder's certificate  | 
 | 
     * @param date the time the validity of the OCSP responder's certificate  | 
 | 
     *    should be checked against. If null, the current time is used.  | 
 | 
     * @return the RevocationStatus  | 
 | 
     * @throws IOException if there is an exception connecting to or  | 
 | 
     *    communicating with the OCSP responder  | 
 | 
     * @throws CertPathValidatorException if an exception occurs while  | 
 | 
     *    encoding the OCSP Request or validating the OCSP Response  | 
 | 
     */  | 
 | 
 | 
 | 
      | 
 | 
    public static RevocationStatus check(X509Certificate cert,  | 
 | 
                                         X509Certificate issuerCert,  | 
 | 
                                         URI responderURI,  | 
 | 
                                         X509Certificate responderCert,  | 
 | 
                                         Date date)  | 
 | 
        throws IOException, CertPathValidatorException  | 
 | 
    { | 
 | 
        return check(cert, issuerCert, responderURI, responderCert, date,  | 
 | 
                     Collections.<Extension>emptyList(),  | 
 | 
                     Validator.VAR_PLUGIN_CODE_SIGNING);  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    public static RevocationStatus check(X509Certificate cert,  | 
 | 
            X509Certificate issuerCert, URI responderURI,  | 
 | 
            X509Certificate responderCert, Date date, List<Extension> extensions,  | 
 | 
            String variant)  | 
 | 
        throws IOException, CertPathValidatorException  | 
 | 
    { | 
 | 
        return check(cert, responderURI, null, issuerCert, responderCert, date,  | 
 | 
                extensions, variant);  | 
 | 
    }  | 
 | 
 | 
 | 
    public static RevocationStatus check(X509Certificate cert,  | 
 | 
            URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,  | 
 | 
            X509Certificate responderCert, Date date,  | 
 | 
            List<Extension> extensions, String variant)  | 
 | 
            throws IOException, CertPathValidatorException  | 
 | 
    { | 
 | 
        CertId certId;  | 
 | 
        try { | 
 | 
            X509CertImpl certImpl = X509CertImpl.toImpl(cert);  | 
 | 
            certId = new CertId(issuerCert, certImpl.getSerialNumberObject());  | 
 | 
        } catch (CertificateException | IOException e) { | 
 | 
            throw new CertPathValidatorException  | 
 | 
                ("Exception while encoding OCSPRequest", e); | 
 | 
        }  | 
 | 
        OCSPResponse ocspResponse = check(Collections.singletonList(certId),  | 
 | 
                responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),  | 
 | 
                responderCert, date, extensions, variant);  | 
 | 
        return (RevocationStatus) ocspResponse.getSingleResponse(certId);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static OCSPResponse check(List<CertId> certIds, URI responderURI,  | 
 | 
                              OCSPResponse.IssuerInfo issuerInfo,  | 
 | 
                              X509Certificate responderCert, Date date,  | 
 | 
                              List<Extension> extensions, String variant)  | 
 | 
        throws IOException, CertPathValidatorException  | 
 | 
    { | 
 | 
        byte[] nonce = null;  | 
 | 
        for (Extension ext : extensions) { | 
 | 
            if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) { | 
 | 
                nonce = ext.getValue();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        OCSPResponse ocspResponse = null;  | 
 | 
        try { | 
 | 
            byte[] response = getOCSPBytes(certIds, responderURI, extensions);  | 
 | 
            ocspResponse = new OCSPResponse(response);  | 
 | 
 | 
 | 
              | 
 | 
            ocspResponse.verify(certIds, issuerInfo, responderCert, date,  | 
 | 
                    nonce, variant);  | 
 | 
        } catch (IOException ioe) { | 
 | 
            throw new CertPathValidatorException(  | 
 | 
                "Unable to determine revocation status due to network error",  | 
 | 
                ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);  | 
 | 
        }  | 
 | 
 | 
 | 
        return ocspResponse;  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,  | 
 | 
            List<Extension> extensions) throws IOException { | 
 | 
        OCSPRequest request = new OCSPRequest(certIds, extensions);  | 
 | 
        byte[] bytes = request.encodeBytes();  | 
 | 
 | 
 | 
        InputStream in = null;  | 
 | 
        OutputStream out = null;  | 
 | 
        byte[] response = null;  | 
 | 
 | 
 | 
        try { | 
 | 
            URL url = responderURI.toURL();  | 
 | 
            if (debug != null) { | 
 | 
                debug.println("connecting to OCSP service at: " + url); | 
 | 
            }  | 
 | 
            HttpURLConnection con = (HttpURLConnection)url.openConnection();  | 
 | 
            con.setConnectTimeout(CONNECT_TIMEOUT);  | 
 | 
            con.setReadTimeout(CONNECT_TIMEOUT);  | 
 | 
            con.setDoOutput(true);  | 
 | 
            con.setDoInput(true);  | 
 | 
            con.setRequestMethod("POST"); | 
 | 
            con.setRequestProperty  | 
 | 
                ("Content-type", "application/ocsp-request"); | 
 | 
            con.setRequestProperty  | 
 | 
                ("Content-length", String.valueOf(bytes.length)); | 
 | 
            out = con.getOutputStream();  | 
 | 
            out.write(bytes);  | 
 | 
            out.flush();  | 
 | 
              | 
 | 
            if (debug != null &&  | 
 | 
                con.getResponseCode() != HttpURLConnection.HTTP_OK) { | 
 | 
                debug.println("Received HTTP error: " + con.getResponseCode() | 
 | 
                    + " - " + con.getResponseMessage());  | 
 | 
            }  | 
 | 
            in = con.getInputStream();  | 
 | 
            int contentLength = con.getContentLength();  | 
 | 
            if (contentLength == -1) { | 
 | 
                contentLength = Integer.MAX_VALUE;  | 
 | 
            }  | 
 | 
            response = new byte[contentLength > 2048 ? 2048 : contentLength];  | 
 | 
            int total = 0;  | 
 | 
            while (total < contentLength) { | 
 | 
                int count = in.read(response, total, response.length - total);  | 
 | 
                if (count < 0)  | 
 | 
                    break;  | 
 | 
 | 
 | 
                total += count;  | 
 | 
                if (total >= response.length && total < contentLength) { | 
 | 
                    response = Arrays.copyOf(response, total * 2);  | 
 | 
                }  | 
 | 
            }  | 
 | 
            response = Arrays.copyOf(response, total);  | 
 | 
        } finally { | 
 | 
            if (in != null) { | 
 | 
                try { | 
 | 
                    in.close();  | 
 | 
                } catch (IOException ioe) { | 
 | 
                    throw ioe;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (out != null) { | 
 | 
                try { | 
 | 
                    out.close();  | 
 | 
                } catch (IOException ioe) { | 
 | 
                    throw ioe;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return response;  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * Returns the URI of the OCSP Responder as specified in the  | 
 | 
     * certificate's Authority Information Access extension, or null if  | 
 | 
     * not specified.  | 
 | 
     *  | 
 | 
     * @param cert the certificate  | 
 | 
     * @return the URI of the OCSP Responder, or null if not specified  | 
 | 
     */  | 
 | 
      | 
 | 
    public static URI getResponderURI(X509Certificate cert) { | 
 | 
        try { | 
 | 
            return getResponderURI(X509CertImpl.toImpl(cert));  | 
 | 
        } catch (CertificateException ce) { | 
 | 
              | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static URI getResponderURI(X509CertImpl certImpl) { | 
 | 
 | 
 | 
          | 
 | 
        AuthorityInfoAccessExtension aia =  | 
 | 
            certImpl.getAuthorityInfoAccessExtension();  | 
 | 
        if (aia == null) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
 | 
 | 
        List<AccessDescription> descriptions = aia.getAccessDescriptions();  | 
 | 
        for (AccessDescription description : descriptions) { | 
 | 
            if (description.getAccessMethod().equals(  | 
 | 
                AccessDescription.Ad_OCSP_Id)) { | 
 | 
 | 
 | 
                GeneralName generalName = description.getAccessLocation();  | 
 | 
                if (generalName.getType() == GeneralNameInterface.NAME_URI) { | 
 | 
                    URIName uri = (URIName) generalName.getName();  | 
 | 
                    return uri.getURI();  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static interface RevocationStatus { | 
 | 
        public enum CertStatus { GOOD, REVOKED, UNKNOWN }; | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        CertStatus getCertStatus();  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        Date getRevocationTime();  | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        CRLReason getRevocationReason();  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        Map<String, Extension> getSingleExtensions();  | 
 | 
    }  | 
 | 
}  |