ocspvalidatorimpl.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 380 行

JAVA
380
字号
/* * * * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER *  * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. *  * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). *  * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA *  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */package com.sun.midp.pki.ocsp;import com.sun.midp.io.Base64;import com.sun.midp.main.Configuration;import com.sun.midp.pki.ObjectIdentifier;import com.sun.midp.pki.X509Certificate;import com.sun.midp.pki.DerOutputStream;import com.sun.midp.pki.DerValue;import com.sun.midp.pki.AuthorityInfoAccessEntry;import com.sun.midp.pki.Extension;import com.sun.midp.publickeystore.WebPublicKeyStore;import com.sun.midp.publickeystore.PublicKeyInfo;import com.sun.midp.security.Permissions;import com.sun.midp.crypto.SecureRandom;import com.sun.midp.crypto.NoSuchAlgorithmException;import javax.microedition.pki.Certificate;import javax.microedition.io.HttpConnection;import javax.microedition.io.Connector;import javax.microedition.io.ConnectionNotFoundException;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import java.util.Vector;/** * Validates the certificates. */public class OCSPValidatorImpl implements OCSPValidator {    private static final String OCSP_REQUEST_MIME_TYPE =            "application/ocsp-request";    private static final String OCSP_RESPONSE_MIME_TYPE =            "application/ocsp-response";    /** Connection to OCSP responder. */    private HttpConnection httpConnection;    /** Output stream to send a request to OCSP server. */    private OutputStream httpOutputStream;    /** Input stream to read a response from OCSP server. */    private InputStream httpInputStream;    /** Supported extensions: nonce. */    private static final int OCSP_NONCE_DATA[] = {        1, 3, 6, 1, 5, 5, 7, 48, 1, 2    };        /** nonce extension OID. */    private static final ObjectIdentifier OCSP_NONCE_OID;    /** Size of nonce number, in bytes */    private static final int NONCE_SIZE = 30;    /** Initial size of buffer that is used when receiving HTTP response. */    private static final int CHUNK_SIZE = 10 * 1024;    static {        OCSP_NONCE_OID = ObjectIdentifier.newInternal(OCSP_NONCE_DATA);    }    /**     * Retrieves the status of the given certificate.     *     * @param cert X.509 certificate status of which must be checked     * @param issuerCert certificate of the trusted authority issued     *                   the certificate given by cert     * @return status of the certificate     * @throws OCSPException if the OCSP Responder returned an error message     */    public int checkCertStatus(Certificate cert, Certificate issuerCert)            throws OCSPException {        try {            Vector authInfoAccess =                    ((X509Certificate)cert).getAuthorityInfoAccess(                            AuthorityInfoAccessEntry.ACCESS_METHOD_OCSP);            String responderUrl;            if (authInfoAccess != null && authInfoAccess.size() > 0) {                responderUrl = ((AuthorityInfoAccessEntry)                        authInfoAccess.elementAt(0)).getAccessLocation();            } else {                /*                 * IMPL_NOTE: in our implementation the certificates not                 *     containing AuthorityInfoAccess extension are not                 *     checked using OCSP, so we should never get here.                 *     To change this behavior, the following code block:                   *         "if (cert.getAuthAccessLocation() == null)"                 *     should be removed in VerifierImpl.checkCertChain().                 */                responderUrl = Configuration.getProperty("ocsp.responderURL");            }            openConnection(responderUrl);            // add nonce extension            DerOutputStream tmp = new DerOutputStream();            byte[] nonce = generateNonce();            tmp.write(DerValue.tag_OctetString, nonce);            Extension[] requestExtensions = new Extension[1];            requestExtensions[0] =                new Extension(OCSP_NONCE_OID, false, tmp.toByteArray());            OCSPRequest request =                    new OCSPRequest((X509Certificate)cert,                            (X509Certificate)issuerCert, requestExtensions);            sendRequest(request);            // certId field becomes valid only after the request is sent            // or after getRequestAsByteArray() is called            CertId certId = request.getCertId();            // preparing a vector of all trusted CAs             WebPublicKeyStore keyStore = WebPublicKeyStore.getTrustedKeyStore();            Vector keys = keyStore.getKeys();            Vector caCerts = new Vector();            caCerts.addElement(issuerCert);            for (int i = 0; i < keys.size(); i++) {                PublicKeyInfo ki = (PublicKeyInfo)keys.elementAt(i);                if (ki.isEnabled() && Permissions.isTrusted(ki.getDomain())) {                    caCerts.addElement(WebPublicKeyStore.createCertificate(ki));                }            }            OCSPResponse response = receiveResponse(caCerts, certId,                    (X509Certificate)issuerCert, nonce);            // Check that response applies to the cert that was supplied            if (! certId.equals(response.getCertId())) {                throw new OCSPException(OCSPException.CANNOT_VERIFY_SIGNATURE,                    "Certificate in the OCSP response does not match the " +                    "certificate supplied in the OCSP request.");            }            return response.getCertStatus();        } catch (OCSPException e) {            // e.printStackTrace();            throw e;        } catch (Exception e) {            throw new OCSPException(OCSPException.UNKNOWN_ERROR,                                    e.getMessage());        } finally {            cleanup();        }    }    /**     * Opens a connection to the OCSP server.     *     * @param responderUrl URL of the OCSP server to establish connection with     * @throws OCSPException if the connection can't be established     */    private void openConnection(String responderUrl) throws OCSPException {        // IMPL_NOTE: currently proxyUsername and proxyPassword are not used.         String proxyUsername = null, proxyPassword = null;        try {            httpConnection = (HttpConnection)                Connector.open(responderUrl, Connector.READ_WRITE);            httpConnection.setRequestMethod(HttpConnection.POST);            if (proxyUsername != null && proxyPassword != null) {                httpConnection.setRequestProperty("Proxy-Authorization",                    formatAuthCredentials(proxyUsername, proxyPassword));            }        } catch (ConnectionNotFoundException e) {            throw new OCSPException(OCSPException.SERVER_NOT_FOUND);        } catch (IOException ioe) {            throw new OCSPException(OCSPException.CANNOT_OPEN_CONNECTION,                                    ioe.getMessage());        }    }    /**     * Sends a request to the OCSP server.     *     * @param request OCSP request to send     * @throws OCSPException if an error occured while sending the request      */    private void sendRequest(OCSPRequest request) throws OCSPException {        try {            byte[] requestBytes = request.getRequestAsByteArray();            httpConnection.setRequestProperty("Accept",                                              OCSP_RESPONSE_MIME_TYPE);            httpConnection.setRequestProperty("Content-Type",                                              OCSP_REQUEST_MIME_TYPE);            httpConnection.setRequestProperty("Content-length",                String.valueOf(requestBytes.length));            httpOutputStream = httpConnection.openOutputStream();            httpOutputStream.write(requestBytes);            int responseCode = httpConnection.getResponseCode();            if (responseCode != HttpConnection.HTTP_OK) {                throw new OCSPException(OCSPException.CANNOT_SEND_REQUEST,                    httpConnection.getResponseMessage() +                            " (" + responseCode + ")");            }        } catch (IOException ioe) {            throw new OCSPException(OCSPException.CANNOT_SEND_REQUEST,                                    ioe.getMessage());        }    }    /**     * Receives a response from the OCSP server.     *     * @param caCerts X.509 certificates of known CAs     * @param reqCertId ID of the certificate specified in the request      * @param issuerCert certificate of the trusted authority issued     *                   the certificate being verified     * @param reqNonce bytes of the nonce extension specified in the OCSP     *                 request; can be NULL     * @return OCSP response received from the server     * @throws OCSPException if an error occured while receiving response     */    private OCSPResponse receiveResponse(Vector caCerts, CertId reqCertId,            X509Certificate issuerCert, byte[] reqNonce) throws OCSPException {        try {            httpInputStream = httpConnection.openInputStream();            int bufSize = CHUNK_SIZE;            byte[] tmpBuf = new byte[bufSize];            int total = 0;            int count = 0;            while (count != -1) {                count = httpInputStream.read(tmpBuf, total,                                             tmpBuf.length - total);                if (count > 0) {                    total += count;                }                if (total == tmpBuf.length) {                    // allocate more memory to hold the response                    int newBufSize = bufSize + CHUNK_SIZE;                    byte[] newResponseBuf = new byte[newBufSize];                    System.arraycopy(tmpBuf, 0, newResponseBuf, 0, total);                    tmpBuf = newResponseBuf;                }            }            byte[] responseBuf = new byte[total];            System.arraycopy(tmpBuf, 0, responseBuf, 0, total);            return new OCSPResponse(responseBuf, caCerts, reqCertId,                     issuerCert, WebPublicKeyStore.getTrustedKeyStore(),                    reqNonce);        } catch (IOException ioe) {            throw new OCSPException(OCSPException.SERVER_NOT_RESPONDING,                                    ioe.getMessage());        }    }    /**     * Generates nonce.     *     * IMPL_NOTE: SecureRandom implementation used in this function is based on     *            com.sun.midp.crypto.PRand pseudo random number generator that     *            uses a constant seed. This seed is just an example     *            implementation and IS NOT secure (unpredictable).     *            To make PRand secure, the seed MUST be derived from     *            unpredicatable data in a production device at the native     *            level.     *     * @return nonce as a byte array     */    private static byte[] generateNonce() {        SecureRandom random;        try {            random = SecureRandom.getInstance(SecureRandom.ALG_SECURE_RANDOM);        } catch (NoSuchAlgorithmException e) {            // should not happen: SecureRandom.ALG_SECURE_RANDOM exists            throw new RuntimeException(e.getMessage());        }        byte[] randomData = new byte[NONCE_SIZE];        random.nextBytes(randomData, 0, NONCE_SIZE);        return randomData;    }    /**     * Closes the http connection to the OCSP server and the corresponding     * input and output streams if opened.     */    private void cleanup() {        if (httpInputStream != null) {            try {                httpInputStream.close();            } catch (Exception ex) {                // ignore            }        }        if (httpOutputStream != null) {            try {                httpOutputStream.close();            } catch (Exception ex) {                // ignore            }        }        if (httpConnection != null) {            try {                httpConnection.close();            } catch (Exception ex) {                // ignore            }        }    }    /**     * IMPL_NOTE: copied from OtaNotifier. Will be moved to a common part.     *     * Formats the username and password for HTTP basic authentication     * according RFC 2617.     *     * @param username for HTTP authentication     * @param password for HTTP authentication     *     * @return properly formated basic authentication credential     */    private static String formatAuthCredentials(String username,                                                String password) {        byte[] data = new byte[username.length() + password.length() + 1];        int j = 0;        for (int i = 0; i < username.length(); i++, j++) {            data[j] = (byte)username.charAt(i);        }        data[j] = (byte)':';        j++;        for (int i = 0; i < password.length(); i++, j++) {            data[j] = (byte)password.charAt(i);        }        return "Basic " + Base64.encode(data, 0, data.length);    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?