/*********************************************************************** * * J S S _ O c t e t S t r i n g T o B y t e A r r a y * * Converts a representation of an integer as a big-endian octet string * stored in a SECItem (as used by the low-level crypto functions) to a * representation of an integer as a big-endian Java byte array. Prepends * a zero byte to force it to be positive. Returns NULL if an exception * occurred. * */ jbyteArray JSS_OctetStringToByteArray(JNIEnv *env, SECItem *item) { jbyteArray array; jbyte *bytes; int size; /* size of the resulting byte array */ PR_ASSERT(env != NULL && item->len>0); /* allow space for extra zero byte */ size = item->len+1; array = (*env)->NewByteArray(env, size); if(array == NULL) { ASSERT_OUTOFMEM(env); return NULL; } bytes = (*env)->GetByteArrayElements(env, array, NULL); if(bytes == NULL) { ASSERT_OUTOFMEM(env); return NULL; } /* insert a 0 as the MSByte to force the string to be positive */ bytes[0] = 0; /* now insert the rest of the bytes */ memcpy(bytes+1, item->data, size-1); (*env)->ReleaseByteArrayElements(env, array, bytes, 0); return array; }
JNIEXPORT jintArray JNICALL Java_org_mozilla_jss_ssl_SSLSocket_getImplementedCipherSuites (JNIEnv *env, jclass clazz) { jintArray ciphArray = NULL; jint* arrayRegion = NULL; int i; ciphArray = (*env)->NewIntArray(env, SSL_NumImplementedCiphers); if( ciphArray == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } arrayRegion = (*env)->GetIntArrayElements(env, ciphArray, NULL/*isCopy*/); if( arrayRegion == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } for( i=0; i < SSL_NumImplementedCiphers; ++i) { arrayRegion[i] = SSL_ImplementedCiphers[i]; } finish: if( arrayRegion != NULL ) { (*env)->ReleaseIntArrayElements(env, ciphArray, arrayRegion, 0); } return ciphArray; }
/*********************************************************************** * * J S S _ P K 1 1 _ w r a p P r i v K e y * privk: will be stored in a Java wrapper. * Returns: a new PK11PrivKey, or NULL if an exception occurred. */ jobject JSS_PK11_wrapPrivKey(JNIEnv *env, SECKEYPrivateKey **privk) { jclass keyClass; jmethodID constructor; jbyteArray ptrArray; jobject Key=NULL; const char *className = NULL; PR_ASSERT(env!=NULL && privk!=NULL && *privk!=NULL); /* Find the class */ switch( (*privk)->keyType ) { case rsaKey: className = "org/mozilla/jss/pkcs11/PK11RSAPrivateKey"; break; case dsaKey: className = "org/mozilla/jss/pkcs11/PK11DSAPrivateKey"; break; case ecKey: className = "org/mozilla/jss/pkcs11/PK11ECPrivateKey"; break; default: className = "org/mozilla/jss/pkcs11/PK11PrivKey"; break; } keyClass = (*env)->FindClass(env, className); if(keyClass == NULL) { ASSERT_OUTOFMEM(env); goto finish; } /* find the constructor */ constructor = (*env)->GetMethodID(env, keyClass, "<init>", "([B)V"); if(constructor == NULL) { ASSERT_OUTOFMEM(env); goto finish; } /* convert the pointer to a byte array */ ptrArray = JSS_ptrToByteArray(env, (void*)*privk); if(ptrArray == NULL) { goto finish; } /* call the constructor */ Key = (*env)->NewObject(env, keyClass, constructor, ptrArray); finish: if(Key == NULL) { SECKEY_DestroyPrivateKey(*privk); } *privk = NULL; return Key; }
/*********************************************************************** ** ** 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; } }
/*********************************************************************** * * J S S _ P K 1 1 _ w r a p P K 1 1 T o k e n * * Create a PK11Token object from a PKCS #11 slot. * * slot is a pointer to a PKCS #11 slot, which must not be NULL. It will * be eaten by the wrapper, so you can't use it after you call this. * * Returns a new PK11Token object, or NULL if an exception was thrown. */ jobject JSS_PK11_wrapPK11Token(JNIEnv *env, PK11SlotInfo **slot) { jclass tokenClass; jmethodID constructor; jbyteArray byteArray; jobject Token=NULL; jboolean internal; jboolean keyStorage; PR_ASSERT(env!=NULL && slot!=NULL && *slot!=NULL); internal = (*slot == PK11_GetInternalSlot()); keyStorage = (*slot == PK11_GetInternalKeySlot()); byteArray = JSS_ptrToByteArray(env, (void*)*slot); /* * Lookup the class and constructor */ tokenClass = (*env)->FindClass(env, PK11TOKEN_CLASS_NAME); if(tokenClass == NULL) { ASSERT_OUTOFMEM(env); goto finish; } constructor = (*env)->GetMethodID( env, tokenClass, PK11TOKEN_CONSTRUCTOR_NAME, PK11TOKEN_CONSTRUCTOR_SIG); if(constructor == NULL) { ASSERT_OUTOFMEM(env); goto finish; } /* Call the constructor */ Token = (*env)->NewObject(env, tokenClass, constructor, byteArray, internal, keyStorage); finish: if(Token==NULL) { PK11_FreeSlot(*slot); } *slot = NULL; return Token; }
/*********************************************************************** * * PK11MessageDigest.update * */ JNIEXPORT void JNICALL Java_org_mozilla_jss_pkcs11_PK11MessageDigest_update (JNIEnv *env, jclass clazz, jobject proxyObj, jbyteArray inbufBA, jint offset, jint len) { PK11Context *context = NULL; jbyte* bytes = NULL; if( JSS_PK11_getCipherContext(env, proxyObj, &context) != PR_SUCCESS ) { /* exception was thrown */ goto finish; } PR_ASSERT( (*env)->GetArrayLength(env, inbufBA) >= offset+len ); bytes = (*env)->GetByteArrayElements(env, inbufBA, NULL); if( bytes == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } if( PK11_DigestOp(context, (unsigned char*)(bytes+offset), len) != SECSuccess ) { JSS_throwMsg(env, DIGEST_EXCEPTION, "Digest operation failed"); goto finish; } finish: if(bytes) { (*env)->ReleaseByteArrayElements(env, inbufBA, bytes, JNI_ABORT); } }
/*********************************************************************** ** ** J S S _ t h r o w ** ** 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. ** ** Example: ** JSS_throw(env, ILLEGAL_ARGUMENT_EXCEPTION); ** return -1; */ void JSS_throw(JNIEnv *env, char *throwableClassName) { jclass throwableClass; jobject throwable; jmethodID constructor; jint result; PR_ASSERT( (*env)->ExceptionOccurred(env) == NULL ); /* Lookup the class */ throwableClass = NULL; if(throwableClassName) { throwableClass = (*env)->FindClass(env, throwableClassName); /* make sure the class was found */ PR_ASSERT(throwableClass != NULL); } if(throwableClass == NULL) { throwableClass = (*env)->FindClass(env, GENERIC_EXCEPTION); } PR_ASSERT(throwableClass != NULL); /* Lookup up the plain vanilla constructor */ constructor = (*env)->GetMethodID( env, throwableClass, PLAIN_CONSTRUCTOR, PLAIN_CONSTRUCTOR_SIG); if(constructor == NULL) { /* Anything other than OutOfMemory is a bug */ ASSERT_OUTOFMEM(env); return; } /* Create an instance of the throwable */ throwable = (*env)->NewObject(env, throwableClass, constructor); if(throwable == NULL) { /* Anything other than OutOfMemory is a bug */ ASSERT_OUTOFMEM(env); return; } /* Throw the new instance */ result = (*env)->Throw(env, throwable); PR_ASSERT(result == 0); }
/*********************************************************************** * * J S S _ P K 1 1 _ w r a p S y m K e y * Puts a Symmetric Key into a Java object. * (Does NOT perform a cryptographic "wrap" operation.) * symKey: will be stored in a Java wrapper. * Returns: a new PK11SymKey, or NULL if an exception occurred. */ jobject JSS_PK11_wrapSymKey(JNIEnv *env, PK11SymKey **symKey) { jclass keyClass; jmethodID constructor; jbyteArray ptrArray; jobject Key=NULL; PR_ASSERT(env!=NULL && symKey!=NULL && *symKey!=NULL); /* find the class */ keyClass = (*env)->FindClass(env, PK11SYMKEY_CLASS_NAME); if( keyClass == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } /* find the constructor */ constructor = (*env)->GetMethodID(env, keyClass, PLAIN_CONSTRUCTOR, PK11SYMKEY_CONSTRUCTOR_SIG); if(constructor == NULL) { ASSERT_OUTOFMEM(env); goto finish; } /* convert the pointer to a byte array */ ptrArray = JSS_ptrToByteArray(env, (void*)*symKey); if( ptrArray == NULL ) { goto finish; } /* call the constructor */ Key = (*env)->NewObject(env, keyClass, constructor, ptrArray); finish: if(Key == NULL) { PK11_FreeSymKey(*symKey); } *symKey = NULL; return Key; }
/*********************************************************************** * Copies the contents of a SECItem into a new Java byte array. * * item * A SECItem. Must not be NULL. * RETURNS * A Java byte array. NULL will be returned if an exception was * thrown. */ jbyteArray JSS_SECItemToByteArray(JNIEnv *env, SECItem *item) { jbyteArray array=NULL; PR_ASSERT(env!=NULL && item!=NULL); PR_ASSERT(item->len >= 0); PR_ASSERT(item->len == 0 || item->data != NULL); array = (*env)->NewByteArray(env, item->len); if( array == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } (*env)->SetByteArrayRegion(env, array, 0, item->len, item->data); finish: return array; }
/*********************************************************************** * * 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; }
/*********************************************************************** * * PK11MessageDigest.digest * */ JNIEXPORT jint JNICALL Java_org_mozilla_jss_pkcs11_PK11MessageDigest_digest (JNIEnv *env, jclass clazz, jobject proxyObj, jbyteArray outbuf, jint offset, jint len) { PK11Context *context=NULL; jbyte *bytes=NULL; SECStatus status; unsigned int outLen; if( JSS_PK11_getCipherContext(env, proxyObj, &context) != PR_SUCCESS) { /* exception was thrown */ goto finish; } PR_ASSERT( (*env)->GetArrayLength(env, outbuf) >= offset+len ); bytes = (*env)->GetByteArrayElements(env, outbuf, NULL); if( bytes == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } status = PK11_DigestFinal(context, (unsigned char*)(bytes+offset), &outLen, len); if( status != SECSuccess ) { JSS_throwMsg(env, DIGEST_EXCEPTION, "Error occurred while performing" " digest operation"); goto finish; } finish: if(bytes) { (*env)->ReleaseByteArrayElements(env, outbuf, bytes, 0); } return outLen; }
JNIEXPORT void JNICALL Java_org_mozilla_jss_ssl_SSLSocket_socketConnect (JNIEnv *env, jobject self, jbyteArray addrBA, jstring hostname, jint port) { JSSL_SocketData *sock; PRNetAddr addr; jbyte *addrBAelems = NULL; PRStatus status; int stat; const char *hostnameStr=NULL; if( JSSL_getSockData(env, self, &sock) != PR_SUCCESS) { /* exception was thrown */ goto finish; } /* * setup the PRNetAddr structure */ addr.inet.family = AF_INET; addr.inet.port = htons(port); PR_ASSERT(sizeof(addr.inet.ip) == 4); PR_ASSERT( (*env)->GetArrayLength(env, addrBA) == 4); addrBAelems = (*env)->GetByteArrayElements(env, addrBA, NULL); if( addrBAelems == NULL ) { ASSERT_OUTOFMEM(env); goto finish; } memcpy(&addr.inet.ip, addrBAelems, 4); /* * Tell SSL the URL we think we want to connect to. * This prevents man-in-the-middle attacks. */ hostnameStr = (*env)->GetStringUTFChars(env, hostname, NULL); if( hostnameStr == NULL ) goto finish; stat = SSL_SetURL(sock->fd, (char*)hostnameStr); if( stat != 0 ) { JSSL_throwSSLSocketException(env, "Failed to set the SSL URL"); goto finish; } /* * make the connect call */ status = PR_Connect(sock->fd, &addr, PR_INTERVAL_NO_TIMEOUT); if( status != PR_SUCCESS) { JSSL_throwSSLSocketException(env, "Unable to connect"); goto finish; } finish: /* This method should never be called on a Java socket wrapper. */ PR_ASSERT( sock==NULL || sock->jsockPriv==NULL); if( hostnameStr != NULL ) { (*env)->ReleaseStringUTFChars(env, hostname, hostnameStr); } if( addrBAelems != NULL ) { (*env)->ReleaseByteArrayElements(env, addrBA, addrBAelems, JNI_ABORT); } }
/*********************************************************************** * 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; }