/***********************************************************************
 * J S S _ B y t e A r r a y T o S E C I t e m
 *
 * Copies the contents of a Java byte array into a new SECItem.
 *
 * byteArray
 *      A Java byte array. Must not be NULL.
 * RETURNS
 *      A newly allocated SECItem, or NULL iff an exception was thrown.
 */
SECItem*
JSS_ByteArrayToSECItem(JNIEnv *env, jbyteArray byteArray)
{
    SECItem *item = NULL;

    PR_ASSERT(env!=NULL && byteArray!=NULL);

    /* Create a new SECItem */
    item = PR_NEW(SECItem);
    if( item == NULL ) {
        JSS_throw(env, OUT_OF_MEMORY_ERROR);
        goto finish;
    }

    /* Setup the length, allocate the buffer */
    item->len = (*env)->GetArrayLength(env, byteArray);
    item->data = PR_Malloc(item->len);

    /* copy the bytes from the byte array into the SECItem */
    (*env)->GetByteArrayRegion(env, byteArray, 0, item->len,
                (jbyte*)item->data);
    if( (*env)->ExceptionOccurred(env) ) {
        SECITEM_FreeItem(item, PR_TRUE /*freeit*/);
        item = NULL;
    }

finish:
    return item;
}
/***********************************************************************
**
** J S S _ t h r o w M s g P r E r r A r g
**
** Throw an exception in native code.  You should return right after
** calling this function.
**
** throwableClassName is the name of the throwable you are throwing in
** JNI class name format (xxx/xx/xxx/xxx). It must not be NULL.
**
** message is the message parameter of the throwable. It must not be NULL.
** If you don't have a message, call JSS_throw.
**
** errCode is a PRErrorCode returned from PR_GetError().
**
** Example:
**      JSS_throwMsg(env, ILLEGAL_ARGUMENT_EXCEPTION, PR_GetError());
**      return -1;
*/
void
JSS_throwMsgPrErrArg(JNIEnv *env, char *throwableClassName, char *message,
    PRErrorCode errCode)
{
    const char *errStr = JSS_strerror(errCode);
    char *msg = NULL;
    int msgLen;

    if( errStr == NULL ) {
        errStr = "Unknown error";
    }

    msgLen = strlen(message) + strlen(errStr) + 40;
    msg = PR_Malloc(msgLen);
    if( msg == NULL ) {
        JSS_throw(env, OUT_OF_MEMORY_ERROR);
        goto finish;
    }
    PR_snprintf(msg, msgLen, "%s: (%ld) %s", message, errCode, errStr);

    JSS_throwMsg(env, throwableClassName, msg);

finish:
    if(msg != NULL) {
        PR_Free(msg);
    }
}
/***********************************************************************
**
** J S S _ g e t P t r F r o m P r o x y
**
** Given a NativeProxy, extract the pointer and store it at the given
** address.
**
** nativeProxy: a JNI reference to a NativeProxy.
** ptr: address of a void* that will receive the pointer extracted from
**      the NativeProxy.
** Returns: PR_SUCCESS on success, PR_FAILURE if an exception was thrown.
**
** Example:
**  DataStructure *recovered;
**  jobject proxy;
**  JNIEnv *env;
**  [...]
**  if(JSS_getPtrFromProxy(env, proxy, (void**)&recovered) != PR_SUCCESS) {
**      return;  // exception was thrown!
**  }
*/
PRStatus
JSS_getPtrFromProxy(JNIEnv *env, jobject nativeProxy, void **ptr)
{
    jclass nativeProxyClass;
	jclass proxyClass;
    jfieldID byteArrayField;
    jbyteArray byteArray;
    int size;

    PR_ASSERT(env!=NULL && nativeProxy != NULL && ptr != NULL);
    if( nativeProxy == NULL ) {
        JSS_throw(env, NULL_POINTER_EXCEPTION);
        return PR_FAILURE;
    }

	proxyClass = (*env)->GetObjectClass(env, nativeProxy);
	PR_ASSERT(proxyClass != NULL);

#ifdef DEBUG
    nativeProxyClass = (*env)->FindClass(
								env,
								NATIVE_PROXY_CLASS_NAME);
    if(nativeProxyClass == NULL) {
        ASSERT_OUTOFMEM(env);
        return PR_FAILURE;
    }

    /* make sure what we got was really a NativeProxy object */
    PR_ASSERT( (*env)->IsInstanceOf(env, nativeProxy, nativeProxyClass) );
#endif

    byteArrayField = (*env)->GetFieldID(
								env,
								proxyClass,
								NATIVE_PROXY_POINTER_FIELD,
						        NATIVE_PROXY_POINTER_SIG);
    if(byteArrayField==NULL) {
        ASSERT_OUTOFMEM(env);
        return PR_FAILURE;
    }

    byteArray = (jbyteArray) (*env)->GetObjectField(env, nativeProxy,
                        byteArrayField);
    PR_ASSERT(byteArray != NULL);

    size = sizeof(*ptr);
    PR_ASSERT((*env)->GetArrayLength(env, byteArray) == size);
    (*env)->GetByteArrayRegion(env, byteArray, 0, size, (void*)ptr);
    if( (*env)->ExceptionOccurred(env) ) {
        PR_ASSERT(PR_FALSE);
        return PR_FAILURE;
    } else {
        return PR_SUCCESS;
    }
}
Exemple #4
0
static void
addToVerifyLog(JNIEnv *env, CERTVerifyLog *log, CERTCertificate *cert,
    unsigned long error, unsigned int depth)
{
    CERTVerifyLogNode *node, *tnode;

    PR_ASSERT(log != NULL);

    PL_ARENA_ALLOCATE(node, log->arena, sizeof(CERTVerifyLogNode));
    if ( node == NULL ) {
        JSS_throw(env, OUT_OF_MEMORY_ERROR);
        return;
    }
    node->cert = CERT_DupCertificate(cert);
    node->error = error;
    node->depth = depth;
    node->arg = NULL;

    if ( log->tail == NULL ) {
        /* empty list */
        log->head = log->tail = node;
        node->prev = NULL;
        node->next = NULL;
    } else if ( depth >= log->tail->depth ) {
        /* add to tail */
        node->prev = log->tail;
        log->tail->next = node;
        log->tail = node;
        node->next = NULL;
    } else if ( depth < log->head->depth ) {
        /* add at head */
        node->prev = NULL;
        node->next = log->head;
        log->head->prev = node;
        log->head = node;
    } else {
        /* add in middle */
        tnode = log->tail;
        while ( tnode != NULL ) {
            if ( depth >= tnode->depth ) {
                /* insert after tnode */
                node->prev = tnode;
                node->next = tnode->next;
                tnode->next->prev = node;
                tnode->next = node;
                break;
            }

            tnode = tnode->prev;
        }
    }
    log->count++;
}
/***********************************************************************
 *
 * J S S _ B y t e A r r a y T o O c t e t S t r i n g
 *
 * Converts an integer represented as a big-endian Java byte array to
 * an integer represented as a big-endian octet string in a SECItem.
 *
 * INPUTS
 *      byteArray
 *          A Java byte array containing an integer represented in
 *          big-endian format.  Must not be NULL.
 *      item
 *          Pointer to a SECItem that will be filled with the integer
 *          from the byte array, in big-endian format.
 * RETURNS
 *      PR_SUCCESS if the operation was successful, PR_FAILURE if an exception
 *      was thrown.
 */
PRStatus
JSS_ByteArrayToOctetString(JNIEnv *env, jbyteArray byteArray, SECItem *item)
{
    jbyte *bytes=NULL;
    PRStatus status=PR_FAILURE;
    jsize size;

    PR_ASSERT(env!=NULL && byteArray!=NULL && item!=NULL);

    ZERO_SECITEM(*item);

    size = (*env)->GetArrayLength(env, byteArray);
    PR_ASSERT(size > 0);

    bytes = (*env)->GetByteArrayElements(env, byteArray, NULL);
    if(bytes==NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }

    item->data = (unsigned char*) PR_Malloc(size);
    if(item->data == NULL) {
        JSS_throw(env, OUT_OF_MEMORY_ERROR);
        goto finish;
    }
    item->len = size;

    memcpy(item->data, bytes, size);

    status = PR_SUCCESS;

finish:
    if(bytes) {
        (*env)->ReleaseByteArrayElements(env, byteArray, bytes, JNI_ABORT);
    }
    if(status != PR_SUCCESS) {
        SECITEM_FreeItem(item, PR_FALSE);
    }
    return status;
}
JNIEXPORT void JNICALL 
Java_org_mozilla_jss_ssl_SSLSocket_socketWrite(JNIEnv *env, jobject self, 
    jbyteArray bufBA, jint off, jint len, jint timeout)
{
    JSSL_SocketData *sock = NULL;
    jbyte *buf = NULL;
    jint size;
    PRIntervalTime ivtimeout;
    PRThread *me;
    PRInt32 numwrit;

    if( bufBA == NULL ) {
        JSS_throw(env, NULL_POINTER_EXCEPTION);
        goto finish;
    }

    size = (*env)->GetArrayLength(env, bufBA);
    if( off < 0 || len < 0 || (off+len) > size ) {
        JSS_throw(env, INDEX_OUT_OF_BOUNDS_EXCEPTION);
        goto finish;
    }

    buf = (*env)->GetByteArrayElements(env, bufBA, NULL);
    if( buf == NULL ) {
        goto finish;
    }

    ivtimeout = (timeout > 0) ? PR_MillisecondsToInterval(timeout)
                              : PR_INTERVAL_NO_TIMEOUT;

    /* get the socket */
    if( JSSL_getSockData(env, self, &sock) != PR_SUCCESS ) {
        goto finish;
    }
    /* set the current thread doing the write */
    me = PR_GetCurrentThread();
    PR_Lock(sock->lock);
    if ( sock->closePending ) {
       PR_Unlock(sock->lock);
       JSSL_throwSSLSocketException(env, "Write operation interrupted");
       goto finish;
    }
    PR_ASSERT(sock->writer == NULL);
    sock->writer = me;
    PR_Unlock(sock->lock);

    numwrit = PR_Send(sock->fd, buf+off, len, 0 /*flags*/, ivtimeout);

    PR_Lock(sock->lock);
    PR_ASSERT(sock->writer == me);
    sock->writer = NULL;
    PR_Unlock(sock->lock);

    if( numwrit < 0 ) {
        PRErrorCode err = PR_GetError();
        if( err == PR_PENDING_INTERRUPT_ERROR ) {
#ifdef WINNT
            /* clean up after PR_Interrupt called by abortReadWrite. */
            PR_NT_CancelIo(sock->fd);
#endif 
            JSSL_throwSSLSocketException(env, "Write operation interrupted");
        } else if( err == PR_IO_TIMEOUT_ERROR ) {
#ifdef WINNT
            /*
             * if timeout was set, and the PR_Send() timed out,
             * then cancel the I/O on the socket, otherwise PR_Send()
             * will always return PR_IO_PENDING_ERROR on subsequent
             * calls
             */
            PR_NT_CancelIo(sock->fd);
#endif 
            JSSL_throwSSLSocketException(env, "Operation timed out");
        } else {
            JSSL_throwSSLSocketException(env, "Failed to write to socket");
        }
        goto finish;
    }
    /* PR_Send is supposed to block until it sends everything */
    PR_ASSERT(numwrit == len);

finish:
    if( buf != NULL ) {
        (*env)->ReleaseByteArrayElements(env, bufBA, buf, JNI_ABORT);
    }
    EXCEPTION_CHECK(env, sock)
}
JNIEXPORT jint JNICALL 
Java_org_mozilla_jss_ssl_SSLSocket_socketRead(JNIEnv *env, jobject self, 
    jbyteArray bufBA, jint off, jint len, jint timeout)
{
    JSSL_SocketData *sock = NULL;
    jbyte *buf = NULL;
    jint size;
    PRIntervalTime ivtimeout;
    PRThread *me;
    jint nread = -1;
    
    size = (*env)->GetArrayLength(env, bufBA);
    if( off < 0 || len < 0 || (off+len) > size) {
        JSS_throw(env, INDEX_OUT_OF_BOUNDS_EXCEPTION);
        goto finish;
    }

    buf = (*env)->GetByteArrayElements(env, bufBA, NULL);
    if( buf == NULL ) {
        goto finish;
    }

    ivtimeout = (timeout > 0) ? PR_MillisecondsToInterval(timeout)
                              : PR_INTERVAL_NO_TIMEOUT;

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

    /* set the current thread doing the read */
    me = PR_GetCurrentThread();
    PR_Lock(sock->lock);
    if ( sock->closePending ) {
       PR_Unlock(sock->lock);
       JSSL_throwSSLSocketException(env, "Read operation interrupted");
       goto finish;
    }
    PR_ASSERT(sock->reader == NULL);
    sock->reader = me;
    PR_Unlock(sock->lock);

    nread = PR_Recv(sock->fd, buf+off, len, 0 /*flags*/, ivtimeout);

    PR_Lock(sock->lock);
    PR_ASSERT(sock->reader == me);
    sock->reader = NULL; 
    PR_Unlock(sock->lock);

    if( nread < 0 ) {
        PRErrorCode err = PR_GetError();

        if( err == PR_PENDING_INTERRUPT_ERROR ) {
#ifdef WINNT
            /* Clean up after PR_interrupt called by abortReadWrite. */
            PR_NT_CancelIo(sock->fd);
#endif 
            JSSL_throwSSLSocketException(env, "Read operation interrupted");
        } else if( err == PR_IO_TIMEOUT_ERROR ) {
#ifdef WINNT
            /*
             * if timeout was set, and the PR_Recv timed out,
             * then cancel the I/O on the socket, otherwise PR_Recv()
             * will always return PR_IO_PENDING_ERROR on subsequent
             * calls
             */
            PR_NT_CancelIo(sock->fd);
#endif
            JSSL_throwSSLSocketException(env, "Operation timed out");
        } else {
            JSSL_throwSSLSocketException(env, "Error reading from socket");
        }
        goto finish;
    }

    if( nread == 0 ) {
        /* EOF in Java is -1 */
        nread = -1;
    }

finish:
    EXCEPTION_CHECK(env, sock)
    (*env)->ReleaseByteArrayElements(env, bufBA, buf,
        (nread>0) ? 0 /*copy and free*/ : JNI_ABORT /*free, no copy*/);
    return nread;
}
/***********************************************************************
 * Class:     org_mozilla_jss_util_Password
 * Method:    readPasswordFromConsole
 * Signature: ()Lorg/mozilla/jss/util/Password;
 */
JNIEXPORT jobject JNICALL Java_org_mozilla_jss_util_Password_readPasswordFromConsole
  (JNIEnv *env, jclass clazz)
{
    char *pw=NULL;
    int pwlen;
    jclass pwClass;
    jmethodID pwConstructor;
    jcharArray pwCharArray=NULL;
    jchar *pwChars=NULL;
    jobject password=NULL;
    jboolean pwIsCopy;
    int i;

    /***************************************************
     * Get JNI IDs
     ***************************************************/
    pwClass = (*env)->FindClass(env, PASSWORD_CLASS_NAME);
    if(pwClass == NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }
    pwConstructor = (*env)->GetMethodID(env,
                                        pwClass,
                                        PLAIN_CONSTRUCTOR,
                                        PASSWORD_CONSTRUCTOR_SIG);
    if(pwConstructor == NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }

    /***************************************************
     * Get the password from the console
     ***************************************************/
    pw = getPWFromConsole();

    if(pw == NULL) {
        JSS_throw(env, GIVE_UP_EXCEPTION);
        goto finish;
    }
    pwlen = strlen(pw);
    PR_ASSERT(pwlen > 0);

    /***************************************************
     * Put the password into a char array
     ***************************************************/
    pwCharArray = (*env)->NewCharArray(env, pwlen);
    if(pwCharArray == NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }
    pwChars = (*env)->GetCharArrayElements(env, pwCharArray, &pwIsCopy);
    if(pwChars == NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }
    for(i=0; i < pwlen; i++) {
        /* YUK! Only works for ASCII. */
        pwChars[i] = pw[i];
    }

    if( pwIsCopy ) {
        /* copy back the changes */
        (*env)->ReleaseCharArrayElements(env, pwCharArray, pwChars, JNI_COMMIT);
        /* clear the copy */
        memset(pwChars, 0, pwlen);
        /* release the copy */
        (*env)->ReleaseCharArrayElements(env, pwCharArray, pwChars, JNI_ABORT);
    } else {
        /* pwChars is not a copy, so this should be a no-op, but we include
         * it anyway */
        (*env)->ReleaseCharArrayElements(env, pwCharArray, pwChars, 0);
    }
    pwChars = NULL;

    /***************************************************
     * Construct a new Password from the char array
     ***************************************************/
    password = (*env)->NewObject(env, pwClass, pwConstructor, pwCharArray);
    if(password == NULL) {
        ASSERT_OUTOFMEM(env);
        goto finish;
    }

finish:
    if(pw != NULL) {
        memset(pw, 0, strlen(pw));
        PR_Free(pw);
    }
    return password;
}