Пример #1
0
/*
 * Callback from SSL for checking a (possibly) expired
 * certificate the peer presents.
 *
 * obj - a jobject -> instance of a class implementing 
 *       the SSLCertificateApprovalCallback interface
 */
SECStatus
JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig,
             PRBool isServer)
{
    CERTCertificate *peerCert=NULL;
    CERTVerifyLog log;
    JNIEnv *env;
    jobject validityStatus;
    jmethodID addReasonMethod;
    int certUsage;
    int checkcn_rv;
    jmethodID approveMethod;
    jboolean result;
    char *hostname=NULL;
    SECStatus retval = SECFailure;
    SECStatus verificationResult;

    PR_ASSERT(arg != NULL);
    PR_ASSERT(fd != NULL);

    /* initialize logging structures */
    log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if( log.arena == NULL ) return SECFailure;
    log.head = NULL;
    log.tail = NULL;
    log.count = 0;

    /* get the JNI environment */
    if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){
        PR_ASSERT(PR_FALSE);
        goto finish;
    }

    /* First, get a handle on the cert that the peer presented */
    peerCert = SSL_PeerCertificate(fd);
    
    /* if peer didn't present a cert, why am I called? */
    if (peerCert == NULL) goto finish;

    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;

    /* 
     * verify it against current time - (can't use
     * CERT_VerifyCertNow() since it doesn't allow passing of
     * logging parameter)
     */

    verificationResult = CERT_VerifyCert(   CERT_GetDefaultCertDB(),
                            peerCert,
                            checkSig,
                            certUsage,
                            PR_Now(),
                            NULL /*pinarg*/,
                            &log);

    if (verificationResult == SECSuccess && log.count > 0) {
        verificationResult = SECFailure;
    }

    /*
     * Verify the domain name of the cert.
     */
    hostname = SSL_RevealURL(fd);    /* really is a hostname, not a URL */
    if (hostname && hostname[0]) {
        checkcn_rv = CERT_VerifyCertName(peerCert, hostname);
        PORT_Free(hostname);
    } else {
        checkcn_rv = SECFailure;
    }
    if (checkcn_rv != SECSuccess) {
        addToVerifyLog(env, &log,peerCert,SSL_ERROR_BAD_CERT_DOMAIN,0);
        if((*env)->ExceptionOccurred(env) != NULL) goto finish;
        verificationResult = SECFailure;
    }

    /*
     * create a new ValidityStatus object
     */
    {
        jclass clazz;
        jmethodID cons;

        clazz = (*env)->FindClass(env, SSLCERT_APP_CB_VALIDITY_STATUS_CLASS);
        if( clazz == NULL ) goto finish;

        cons = (*env)->GetMethodID(env, clazz,
                        PLAIN_CONSTRUCTOR, PLAIN_CONSTRUCTOR_SIG);
        if( cons == NULL ) goto finish;

        validityStatus = (*env)->NewObject(env, clazz, cons);
        if( validityStatus == NULL ) {
            goto finish;
        }

        /* get the addReason methodID while we're at it */
        addReasonMethod = (*env)->GetMethodID(env, clazz,
            SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_NAME,
            SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_SIG);
        if( addReasonMethod == NULL ) {
            goto finish;
        }
    }
    
    /*
     * Load up the ValidityStatus object with all the reasons for failure
     */
    if (verificationResult == SECFailure)  {
        CERTVerifyLogNode *node;
        int error;
        CERTCertificate *errorcert=NULL;
        int depth;
        jobject ninjacert;

        node = log.head;
        while (node) {
            error = node->error;
            errorcert = node->cert;
            node->cert = NULL;
            depth = node->depth;

            ninjacert = JSS_PK11_wrapCert(env,&errorcert);
            (*env)->CallVoidMethod(env, validityStatus, addReasonMethod,
                error,
                ninjacert,
                depth
                );

            node = node->next;
        }
    }

    /*
     * Call the approval callback
     */
    {
        jobject approvalCallbackObj;
        jclass approvalCallbackClass;
        jobject peerninjacert;

        approvalCallbackObj = (jobject) arg;

        approvalCallbackClass = (*env)->GetObjectClass(env,approvalCallbackObj);
        approveMethod = (*env)->GetMethodID(
            env,
            approvalCallbackClass,
            SSLCERT_APP_CB_APPROVE_NAME,
            SSLCERT_APP_CB_APPROVE_SIG);
        if( approveMethod == NULL ) {
            PR_ASSERT(PR_FALSE);
            goto finish;
        }

        peerninjacert = JSS_PK11_wrapCert(env,&peerCert);
        if( peerninjacert == NULL) {
            PR_ASSERT(PR_FALSE);
            goto finish;
        }
        result = (*env)->CallBooleanMethod(env, approvalCallbackObj,
            approveMethod, peerninjacert, validityStatus);
        if( result == JNI_TRUE ) {
            retval = SECSuccess;
        }
    }

finish:
    if( peerCert != NULL ) {
        CERT_DestroyCertificate(peerCert);
    }
    PORT_FreeArena(log.arena, PR_FALSE);
    return retval;
}
Пример #2
0
JNIEXPORT jobject JNICALL
Java_org_mozilla_jss_ssl_SSLSocket_getStatus
    (JNIEnv *env, jobject self)
{
    SECStatus secstatus;
    JSSL_SocketData *sock=NULL;
    int on;
    char *cipher=NULL;
    jobject cipherString;
    jint keySize;
    jint secretKeySize;
    char *issuer=NULL;
    jobject issuerString;
    char *subject=NULL;
    jobject subjectString;
    jobject statusObj = NULL;
    jclass statusClass;
    jmethodID statusCons;
    CERTCertificate *peerCert=NULL;
    jobject peerCertObj = NULL;
    char *serialNum = NULL;
    jobject serialNumObj = NULL;

    /* get the fd */
    if( JSSL_getSockData(env, self, &sock) != PR_SUCCESS) {
        /* exception was thrown */
        goto finish;
    }


    /* get the status */
    secstatus = SSL_SecurityStatus( sock->fd,
                                    &on,
                                    &cipher,
                                    (int*)&keySize,
                                    (int*)&secretKeySize,
                                    &issuer,
                                    &subject);

    if(secstatus != SECSuccess) {
        JSSL_throwSSLSocketException(env,
            "Failed to retrieve socket security status");
        goto finish;
    }

    /*
     * get the peer certificate
     */
    peerCert = SSL_PeerCertificate(sock->fd);
    if( peerCert != NULL ) {
        /* the peer cert might be null, for example if this is the server
         * side and the client didn't auth. */

        serialNum = CERT_Hexify(&peerCert->serialNumber, PR_FALSE /*do_colon*/);
        PR_ASSERT(serialNum != NULL);
        serialNumObj = (*env)->NewStringUTF(env, serialNum);
        if( serialNumObj == NULL ) {
            goto finish;
        }

        /* this call will wipe out peerCert */
        peerCertObj = JSS_PK11_wrapCert(env, &peerCert);
        if( peerCertObj == NULL) {
            goto finish;
        }
    }

    /*
     * convert char*s to Java Strings
     */
    cipherString = issuerString = subjectString = NULL;
    if( cipher != NULL ) cipherString = (*env)->NewStringUTF(env, cipher);
    if( issuer != NULL ) issuerString = (*env)->NewStringUTF(env, issuer);
    if( subject != NULL ) subjectString = (*env)->NewStringUTF(env, subject);

    /*
     * package the status into a new SSLSecurityStatus object
     */
    statusClass = (*env)->FindClass(env, SSL_SECURITY_STATUS_CLASS_NAME);
    PR_ASSERT(statusClass != NULL);
    if( statusClass == NULL ) {
        /* exception was thrown */
        goto finish;
    }
    statusCons = (*env)->GetMethodID(env, statusClass,
                            SSL_SECURITY_STATUS_CONSTRUCTOR_NAME,
                            SSL_SECURITY_STATUS_CONSTRUCTOR_SIG);
    PR_ASSERT(statusCons != NULL);
    if(statusCons == NULL ) {
        /* exception was thrown */
        goto finish;
    }
    statusObj = (*env)->NewObject(env, statusClass, statusCons,
            on, cipherString, keySize, secretKeySize, issuerString,
            subjectString, serialNumObj, peerCertObj);
        

finish:
    if( cipher != NULL ) {
        PR_Free(cipher);
    }
    if( issuer != NULL ) {
        PORT_Free(issuer);
    }
    if ( subject != NULL) {
        PORT_Free(subject);
    }
    if( peerCert != NULL ) {
        CERT_DestroyCertificate(peerCert);
    }
    if( serialNum != NULL ) {
        PR_Free(serialNum);
    }

    EXCEPTION_CHECK(env, sock)
    return statusObj;
}