Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6f97792
[Android] Add missing JNI exception checks across crypto PAL (1/3)
simonrozsival May 29, 2026
1430ce4
[Android] Address review feedback: prefer cleanup labels and ReleaseLRef
simonrozsival May 29, 2026
20239b1
[Android] Avoid partial-output state on failure paths
simonrozsival May 29, 2026
bd14e71
[Android] Apply no-partial-state pattern to remaining touched functions
simonrozsival May 29, 2026
b86598b
[Android] Use INIT_LOCALS for jobject locals and avoid partial-output…
simonrozsival May 29, 2026
395fdb3
[Android] Use RELEASE_LOCALS(loc, env) for consistency with surroundi…
simonrozsival May 29, 2026
88556c3
Fix DoUnwrap silently swallowing NewDirectByteBuffer failure
simonrozsival May 29, 2026
4bb471a
Merge branch 'main' into dev/simonrozsival/android-pal-jni-exception-…
simonrozsival Jun 1, 2026
e76a96e
[Android] Release SSLStream context on init failure
simonrozsival Jun 1, 2026
3c30461
[Android] Handle JNI failures in crypto PAL review fixes
simonrozsival Jun 1, 2026
a9da52a
[Android] Guard SSL engine promotion failure
simonrozsival Jun 1, 2026
abe0038
[Android] Check remaining crypto PAL JNI failures
simonrozsival Jun 1, 2026
3e1c617
Merge branch 'main' into dev/simonrozsival/android-pal-jni-exception-…
simonrozsival Jun 8, 2026
d3dfc20
Split GetHandshakeStatus JNI call
Copilot Jun 8, 2026
ae407ce
Release GetHandshakeStatus JNI local
Copilot Jun 8, 2026
0c3cdb0
Preserve GetHandshakeStatus failure ret
Copilot Jun 8, 2026
6134a14
Merge branch 'main' into dev/simonrozsival/android-pal-jni-exception-…
simonrozsival Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,45 +138,48 @@ int32_t AndroidCryptoNative_CipherSetTagLength(CipherCtx* ctx, int32_t tagLength
ARGS_NON_NULL_ALL static int32_t ReinitializeCipher(CipherCtx* ctx)
{
JNIEnv* env = GetJNIEnv();
int32_t ret = FAIL;

INIT_LOCALS(loc, algName, keyBytes, sksObj, ivBytes, ivPsObj);

// SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
// IvParameterSpec ivSpec = new IvParameterSpec(IV); or GCMParameterSpec for GCM/CCM
// cipher.init(encMode, keySpec, ivSpec);

jobject algName = GetAlgorithmName(env, ctx->type);
if (!algName)
return FAIL;
loc[algName] = GetAlgorithmName(env, ctx->type);
if (!loc[algName])
goto cleanup;

int32_t keyLength = ctx->keySizeInBits / 8;
jbyteArray keyBytes = make_java_byte_array(env, keyLength);
(*env)->SetByteArrayRegion(env, keyBytes, 0, keyLength, (jbyte*)ctx->key);
jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, algName);
loc[keyBytes] = make_java_byte_array(env, keyLength);
(*env)->SetByteArrayRegion(env, loc[keyBytes], 0, keyLength, (jbyte*)ctx->key);
loc[sksObj] = (*env)->NewObject(env, g_sksClass, g_sksCtor, loc[keyBytes], loc[algName]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

jobject ivPsObj = NULL;
if (RequiresIV(ctx->type))
{
jbyteArray ivBytes = make_java_byte_array(env, ctx->ivLength);
(*env)->SetByteArrayRegion(env, ivBytes, 0, ctx->ivLength, (jbyte*)ctx->iv);
loc[ivBytes] = make_java_byte_array(env, ctx->ivLength);
(*env)->SetByteArrayRegion(env, loc[ivBytes], 0, ctx->ivLength, (jbyte*)ctx->iv);

if (HasVariableTag(ctx->type))
{
ivPsObj = (*env)->NewObject(env, g_GCMParameterSpecClass, g_GCMParameterSpecCtor, ctx->tagLength * 8, ivBytes);
loc[ivPsObj] = (*env)->NewObject(env, g_GCMParameterSpecClass, g_GCMParameterSpecCtor, ctx->tagLength * 8, loc[ivBytes]);
}
else
{
ivPsObj = (*env)->NewObject(env, g_ivPsClass, g_ivPsCtor, ivBytes);
loc[ivPsObj] = (*env)->NewObject(env, g_ivPsClass, g_ivPsCtor, loc[ivBytes]);
}

(*env)->DeleteLocalRef(env, ivBytes);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
}

(*env)->CallVoidMethod(env, ctx->cipher, g_cipherInitMethod, ctx->encMode, sksObj, ivPsObj);
(*env)->DeleteLocalRef(env, algName);
(*env)->DeleteLocalRef(env, sksObj);
(*env)->DeleteLocalRef(env, ivPsObj);
(*env)->DeleteLocalRef(env, keyBytes);
(*env)->CallVoidMethod(env, ctx->cipher, g_cipherInitMethod, ctx->encMode, loc[sksObj], loc[ivPsObj]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

return CheckJNIExceptions(env) ? FAIL : SUCCESS;
ret = SUCCESS;

cleanup:
RELEASE_LOCALS(loc, env);
return ret;
}

int32_t AndroidCryptoNative_CipherSetKeyAndIV(CipherCtx* ctx, uint8_t* key, uint8_t* iv, int32_t enc)
Expand Down
106 changes: 79 additions & 27 deletions src/native/libs/System.Security.Cryptography.Native.Android/pal_dsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ ARGS_NON_NULL_ALL static jobject GetQParameter(JNIEnv* env, jobject dsa)
INIT_LOCALS(loc, algName, keyFactory, publicKey, publicKeySpec);
loc[algName] = make_java_string(env, "DSA");
loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[algName]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKey] = (*env)->CallObjectMethod(env, dsa, g_keyPairGetPublicMethod);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKeySpec] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGetKeySpecMethod, loc[publicKey], g_DSAPublicKeySpecClass);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

Expand Down Expand Up @@ -90,23 +92,24 @@ int32_t AndroidCryptoNative_DsaSizeP(jobject dsa)
abort_if_invalid_pointer_argument (dsa);

JNIEnv* env = GetJNIEnv();
int32_t bytes = -1;
INIT_LOCALS(loc, algName, keyFactory, publicKey, publicKeySpec, p);
loc[algName] = make_java_string(env, "DSA");
loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[algName]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKey] = (*env)->CallObjectMethod(env, dsa, g_keyPairGetPublicMethod);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKeySpec] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGetKeySpecMethod, loc[publicKey], g_DSAPublicKeySpecClass);
ON_EXCEPTION_PRINT_AND_GOTO(error);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

loc[p] = (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetP);
ON_EXCEPTION_PRINT_AND_GOTO(error);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

int32_t bytes = AndroidCryptoNative_GetBigNumBytes(loc[p]);
RELEASE_LOCALS_ENV(loc, ReleaseLRef);
return bytes;
bytes = AndroidCryptoNative_GetBigNumBytes(loc[p]);

error:
cleanup:
RELEASE_LOCALS_ENV(loc, ReleaseLRef);
return -1;
return bytes;
}

int32_t AndroidCryptoNative_DsaSignatureFieldSize(jobject dsa)
Expand Down Expand Up @@ -217,41 +220,87 @@ int32_t AndroidCryptoNative_GetDsaParameters(
abort_if_invalid_pointer_argument (xLength);

JNIEnv* env = GetJNIEnv();
int32_t ret = FAIL;
int32_t cbP = 0, cbQ = 0, cbG = 0, cbY = 0, cbX = 0;

INIT_LOCALS(loc, algName, keyFactory, publicKey, publicKeySpec, privateKey, privateKeySpec, pBn, qBn, gBn, yBn, xBn);

INIT_LOCALS(loc, algName, keyFactory, publicKey, publicKeySpec, privateKey, privateKeySpec);
*p = *q = *g = *y = *x = NULL;
*pLength = *qLength = *gLength = *yLength = *xLength = 0;

loc[algName] = make_java_string(env, "DSA");
loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[algName]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKey] = (*env)->CallObjectMethod(env, dsa, g_keyPairGetPublicMethod);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[publicKeySpec] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGetKeySpecMethod, loc[publicKey], g_DSAPublicKeySpecClass);
ON_EXCEPTION_PRINT_AND_GOTO(error);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

loc[pBn] = (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetP);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[qBn] = (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetQ);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[gBn] = (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetG);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[yBn] = (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetY);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);

cbP = AndroidCryptoNative_GetBigNumBytes(loc[pBn]);
cbQ = AndroidCryptoNative_GetBigNumBytes(loc[qBn]);
cbG = AndroidCryptoNative_GetBigNumBytes(loc[gBn]);
cbY = AndroidCryptoNative_GetBigNumBytes(loc[yBn]);
if (cbP == FAIL || cbQ == FAIL || cbG == FAIL || cbY == FAIL)
goto cleanup;

Comment thread
simonrozsival marked this conversation as resolved.
*p = ToGRef(env, (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetP));
*q = ToGRef(env, (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetQ));
*g = ToGRef(env, (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetG));
*y = ToGRef(env, (*env)->CallObjectMethod(env, loc[publicKeySpec], g_DSAPublicKeySpecGetY));
*pLength = AndroidCryptoNative_GetBigNumBytes(*p);
*qLength = AndroidCryptoNative_GetBigNumBytes(*q);
*gLength = AndroidCryptoNative_GetBigNumBytes(*g);
*yLength = AndroidCryptoNative_GetBigNumBytes(*y);

*x = NULL;
*xLength = 0;
loc[privateKey] = (*env)->CallObjectMethod(env, dsa, g_keyPairGetPrivateMethod);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
if (loc[privateKey])
{
loc[privateKeySpec] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGetKeySpecMethod, loc[privateKey], g_DSAPrivateKeySpecClass);
ON_EXCEPTION_PRINT_AND_GOTO(error);
*x = ToGRef(env, (*env)->CallObjectMethod(env, loc[privateKeySpec], g_DSAPrivateKeySpecGetX));
*xLength = AndroidCryptoNative_GetBigNumBytes(*x);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
loc[xBn] = (*env)->CallObjectMethod(env, loc[privateKeySpec], g_DSAPrivateKeySpecGetX);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
cbX = AndroidCryptoNative_GetBigNumBytes(loc[xBn]);
if (cbX == FAIL)
goto cleanup;
}

RELEASE_LOCALS_ENV(loc, ReleaseLRef);
return CheckJNIExceptions(env) ? FAIL : SUCCESS;
// Clean up any partially promoted global refs if a later promotion fails.
*p = AddGRef(env, loc[pBn]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
*pLength = cbP;
*q = AddGRef(env, loc[qBn]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
*qLength = cbQ;
*g = AddGRef(env, loc[gBn]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
*gLength = cbG;
*y = AddGRef(env, loc[yBn]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
*yLength = cbY;
if (loc[xBn])
{
*x = AddGRef(env, loc[xBn]);
ON_EXCEPTION_PRINT_AND_GOTO(cleanup);
*xLength = cbX;
}

ret = SUCCESS;

cleanup:
if (ret != SUCCESS)
{
ReleaseGRef(env, *p);
ReleaseGRef(env, *q);
ReleaseGRef(env, *g);
ReleaseGRef(env, *y);
ReleaseGRef(env, *x);
*p = *q = *g = *y = *x = NULL;
*pLength = *qLength = *gLength = *yLength = *xLength = 0;
}

error:
RELEASE_LOCALS_ENV(loc, ReleaseLRef);
return FAIL;
return ret;
}

int32_t AndroidCryptoNative_DsaKeyCreateByExplicitParameters(
Expand Down Expand Up @@ -279,15 +328,18 @@ int32_t AndroidCryptoNative_DsaKeyCreateByExplicitParameters(
bn[G] = AndroidCryptoNative_BigNumFromBinary(g, gLength);
bn[Y] = AndroidCryptoNative_BigNumFromBinary(y, yLength);
loc[publicKeySpec] = (*env)->NewObject(env, g_DSAPublicKeySpecClass, g_DSAPublicKeySpecCtor, bn[Y], bn[P], bn[Q], bn[G]);
ON_EXCEPTION_PRINT_AND_GOTO(error);

if (x)
{
bn[X] = AndroidCryptoNative_BigNumFromBinary(x, xLength);
loc[privateKeySpec] = (*env)->NewObject(env, g_DSAPrivateKeySpecClass, g_DSAPrivateKeySpecCtor, bn[X], bn[P], bn[Q], bn[G]);
ON_EXCEPTION_PRINT_AND_GOTO(error);
}

loc[dsa] = make_java_string(env, "DSA");
loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[dsa]);
ON_EXCEPTION_PRINT_AND_GOTO(error);
loc[publicKey] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGenPublicMethod, loc[publicKeySpec]);
ON_EXCEPTION_PRINT_AND_GOTO(error);

Expand Down
Loading
Loading