/*********************************************************************** * 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; } }
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; }