diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c index a775b0f7552888..b140e84b55e552 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_cipher.c @@ -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) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_dsa.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_dsa.c index e18e87515b05e1..777dbbb3545c46 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_dsa.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_dsa.c @@ -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); @@ -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) @@ -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; - *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( @@ -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); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c index 6b18eddcad17da..09fd6a505a280c 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c @@ -25,70 +25,77 @@ int32_t AndroidCryptoNative_GetECKeyParameters(const EC_KEY* key, abort_if_invalid_pointer_argument (cbD); JNIEnv* env = GetJNIEnv(); + int32_t ret = FAIL; + int32_t cbxBn = 0, cbyBn = 0, cbdBn = 0; - // Get the public key - jobject publicKey = (*env)->CallObjectMethod(env, key->keyPair, g_keyPairGetPublicMethod); + INIT_LOCALS(loc, publicKey, Q, xBn, yBn, privateKey, dBn); - jobject Q = (*env)->CallObjectMethod(env, publicKey, g_ECPublicKeyGetW); + *qx = *qy = NULL; + *cbQx = *cbQy = 0; + *d = NULL; + *cbD = 0; - (*env)->DeleteLocalRef(env, publicKey); + // Get the public key + loc[publicKey] = (*env)->CallObjectMethod(env, key->keyPair, g_keyPairGetPublicMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jobject xBn = (*env)->CallObjectMethod(env, Q, g_ECPointGetAffineX); - jobject yBn = (*env)->CallObjectMethod(env, Q, g_ECPointGetAffineY); + loc[Q] = (*env)->CallObjectMethod(env, loc[publicKey], g_ECPublicKeyGetW); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - (*env)->DeleteLocalRef(env, Q); + loc[xBn] = (*env)->CallObjectMethod(env, loc[Q], g_ECPointGetAffineX); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + loc[yBn] = (*env)->CallObjectMethod(env, loc[Q], g_ECPointGetAffineY); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - // Success; assign variables - *qx = ToGRef(env, xBn); - *cbQx = AndroidCryptoNative_GetBigNumBytes(*qx); - xBn = NULL; - *qy = ToGRef(env, yBn); - *cbQy = AndroidCryptoNative_GetBigNumBytes(*qy); - yBn = NULL; - if (*cbQx == FAIL || *cbQy == FAIL) - goto error; + cbxBn = AndroidCryptoNative_GetBigNumBytes(loc[xBn]); + cbyBn = AndroidCryptoNative_GetBigNumBytes(loc[yBn]); + if (cbxBn == FAIL || cbyBn == FAIL) + goto cleanup; if (includePrivate) { - abort_if_invalid_pointer_argument (d); + loc[privateKey] = (*env)->CallObjectMethod(env, key->keyPair, g_keyPairGetPrivateMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jobject privateKey = (*env)->CallObjectMethod(env, key->keyPair, g_keyPairGetPrivateMethod); + if (!loc[privateKey]) + goto cleanup; - if (!privateKey) - { - *d = NULL; - *cbD = 0; - goto error; - } + loc[dBn] = (*env)->CallObjectMethod(env, loc[privateKey], g_ECPrivateKeyGetS); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jobject dBn = (*env)->CallObjectMethod(env, privateKey, g_ECPrivateKeyGetS); - - (*env)->DeleteLocalRef(env, privateKey); - - *d = ToGRef(env, dBn); - *cbD = AndroidCryptoNative_GetBigNumBytes(*d); - if (*cbD == FAIL) - goto error; + cbdBn = AndroidCryptoNative_GetBigNumBytes(loc[dBn]); + if (cbdBn == FAIL) + goto cleanup; } - else - { - if (d) - *d = NULL; - if (cbD) - *cbD = 0; + // Clean up any partially promoted global refs if a later promotion fails. + *qx = AddGRef(env, loc[xBn]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + *cbQx = cbxBn; + *qy = AddGRef(env, loc[yBn]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + *cbQy = cbyBn; + if (includePrivate) + { + *d = AddGRef(env, loc[dBn]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + *cbD = cbdBn; } - return SUCCESS; + ret = SUCCESS; -error: - *cbQx = *cbQy = 0; - *qx = *qy = 0; - if (d) - *d = NULL; - if (cbD) - *cbD = 0; - return FAIL; +cleanup: + if (ret != SUCCESS) + { + ReleaseGRef(env, *qx); + ReleaseGRef(env, *qy); + ReleaseGRef(env, *d); + *qx = *qy = *d = NULL; + *cbQx = *cbQy = *cbD = 0; + } + + RELEASE_LOCALS_ENV(loc, ReleaseLRef); + return ret; } int32_t AndroidCryptoNative_GetECCurveParameters(const EC_KEY* key, @@ -148,16 +155,21 @@ int32_t AndroidCryptoNative_GetECCurveParameters(const EC_KEY* key, goto error; loc[group] = (*env)->CallObjectMethod(env, key->curveParameters, g_ECParameterSpecGetCurve); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[A] = (*env)->CallObjectMethod(env, loc[group], g_EllipticCurveGetA); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[B] = (*env)->CallObjectMethod(env, loc[group], g_EllipticCurveGetB); + ON_EXCEPTION_PRINT_AND_GOTO(error); loc[field] = (*env)->CallObjectMethod(env, loc[group], g_EllipticCurveGetField); + ON_EXCEPTION_PRINT_AND_GOTO(error); if ((*env)->IsInstanceOf(env, loc[field], g_ECFieldF2mClass)) { *curveType = Characteristic2; // Get the reduction polynomial p bn[P] = (*env)->CallObjectMethod(env, loc[field], g_ECFieldF2mGetReductionPolynomial); + ON_EXCEPTION_PRINT_AND_GOTO(error); } else { @@ -165,26 +177,35 @@ int32_t AndroidCryptoNative_GetECCurveParameters(const EC_KEY* key, *curveType = PrimeShortWeierstrass; // Get the prime p bn[P] = (*env)->CallObjectMethod(env, loc[field], g_ECFieldFpGetP); + ON_EXCEPTION_PRINT_AND_GOTO(error); } // Extract gx and gy loc[G] = (*env)->CallObjectMethod(env, key->curveParameters, g_ECParameterSpecGetGenerator); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[X] = (*env)->CallObjectMethod(env, loc[G], g_ECPointGetAffineX); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[Y] = (*env)->CallObjectMethod(env, loc[G], g_ECPointGetAffineY); + ON_EXCEPTION_PRINT_AND_GOTO(error); // Extract order (n) bn[ORDER] = (*env)->CallObjectMethod(env, key->curveParameters, g_ECParameterSpecGetOrder); + ON_EXCEPTION_PRINT_AND_GOTO(error); // Extract cofactor (h) int32_t cofactorInt = (*env)->CallIntMethod(env, key->curveParameters, g_ECParameterSpecGetCofactor); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[COFACTOR] = (*env)->CallStaticObjectMethod(env, g_bigNumClass, g_valueOfMethod, (int64_t)cofactorInt); + ON_EXCEPTION_PRINT_AND_GOTO(error); // Extract seed (optional) loc[seedArray] = (*env)->CallObjectMethod(env, loc[group], g_EllipticCurveGetSeed); + ON_EXCEPTION_PRINT_AND_GOTO(error); if (loc[seedArray]) { bn[SEED] = (*env)->NewObject(env, g_bigNumClass, g_bigNumCtorWithSign, 1, loc[seedArray]); + ON_EXCEPTION_PRINT_AND_GOTO(error); *seed = ToGRef(env, bn[SEED]); *cbSeed = AndroidCryptoNative_GetBigNumBytes(*seed); @@ -270,8 +291,10 @@ static jobject CreateKeyPairFromCurveParameters( goto error; loc[pubKeyPoint] = (*env)->NewObject(env, g_ECPointClass, g_ECPointCtor, bn[QX], bn[QY]); + ON_EXCEPTION_PRINT_AND_GOTO(error); loc[pubKeySpec] = (*env)->NewObject(env, g_ECPublicKeySpecClass, g_ECPublicKeySpecCtor, loc[pubKeyPoint], curveParameters); + ON_EXCEPTION_PRINT_AND_GOTO(error); // Set private key (optional) if (d && dLength) @@ -281,6 +304,7 @@ static jobject CreateKeyPairFromCurveParameters( goto error; loc[privKeySpec] = (*env)->NewObject(env, g_ECPrivateKeySpecClass, g_ECPrivateKeySpecCtor, bn[D], curveParameters); + ON_EXCEPTION_PRINT_AND_GOTO(error); } } // If we don't have the public key but we have the private key, we can @@ -292,6 +316,7 @@ static jobject CreateKeyPairFromCurveParameters( goto error; loc[privKeySpec] = (*env)->NewObject(env, g_ECPrivateKeySpecClass, g_ECPrivateKeySpecCtor, bn[D], curveParameters); + ON_EXCEPTION_PRINT_AND_GOTO(error); // Java doesn't have a public implementation of operations on points on an elliptic curve // so we can't yet derive a new public key from the private key and generator. @@ -306,6 +331,7 @@ static jobject CreateKeyPairFromCurveParameters( // Create the private and public keys and put them into a key pair. loc[algorithmName] = make_java_string(env, "EC"); loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[algorithmName]); + ON_EXCEPTION_PRINT_AND_GOTO(error); loc[publicKey] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGenPublicMethod, loc[pubKeySpec]); ON_EXCEPTION_PRINT_AND_GOTO(error); @@ -374,26 +400,37 @@ int32_t AndroidCryptoNative_EcKeyCreateByKeyParameters(EC_KEY** key, } // Converts a java.math.BigInteger to a positive int32_t value. -// Returns -1 if bigInteger < 0 or > INT32_MAX +// Returns -1 if bigInteger < 0 or > INT32_MAX, or if a pending JNI exception is detected. ARGS_NON_NULL_ALL static int32_t ConvertBigIntegerToPositiveInt32(JNIEnv* env, jobject bigInteger) { + int32_t ret = -1; + jobject int32MaxBigInt = NULL; + + jint signum = (*env)->CallIntMethod(env, bigInteger, g_sigNumMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + // bigInteger is negative. - if ((*env)->CallIntMethod(env, bigInteger, g_sigNumMethod) < 0) - { - return -1; - } + if (signum < 0) + goto cleanup; + + int32MaxBigInt = (*env)->CallStaticObjectMethod(env, g_bigNumClass, g_valueOfMethod, (int64_t)INT32_MAX); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jobject int32MaxBigInt = (*env)->CallStaticObjectMethod(env, g_bigNumClass, g_valueOfMethod, (int64_t)INT32_MAX); int willOverflow = (*env)->CallIntMethod(env, bigInteger, g_compareToMethod, int32MaxBigInt); - (*env)->DeleteLocalRef(env, int32MaxBigInt); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); // If bigInteger > int32MaxBigInt, then a conversion to int32_t would be lossy. if (willOverflow > 0) - { - return -1; - } + goto cleanup; - return (*env)->CallIntMethod(env, bigInteger, g_intValueMethod); + jint result = (*env)->CallIntMethod(env, bigInteger, g_intValueMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + ret = result; + +cleanup: + ReleaseLRef(env, int32MaxBigInt); + return ret; } EC_KEY* AndroidCryptoNative_EcKeyCreateByExplicitParameters(ECCurveType curveType, @@ -435,7 +472,7 @@ EC_KEY* AndroidCryptoNative_EcKeyCreateByExplicitParameters(ECCurveType curveTyp EC_KEY* keyInfo = NULL; jobject keyPair = NULL; - INIT_LOCALS(loc, G, field, group, paramSpec, seedArray); + INIT_LOCALS(loc, G, field, group, paramSpec, seedArray, ec, keyPairGenerator); INIT_LOCALS(bn, P, A, B, GX, GY, ORDER, COFACTOR); // Java only supports Weierstrass and characteristic-2 type curves. @@ -489,16 +526,19 @@ EC_KEY* AndroidCryptoNative_EcKeyCreateByExplicitParameters(ECCurveType curveTyp loc[seedArray] = make_java_byte_array(env, seedLength); (*env)->SetByteArrayRegion(env, loc[seedArray], 0, seedLength, (jbyte*)seed); loc[group] = (*env)->NewObject(env, g_EllipticCurveClass, g_EllipticCurveCtorWithSeed, loc[field], bn[A], bn[B], loc[seedArray]); + ON_EXCEPTION_PRINT_AND_GOTO(error); } else { loc[group] = (*env)->NewObject(env, g_EllipticCurveClass, g_EllipticCurveCtor, loc[field], bn[A], bn[B]); + ON_EXCEPTION_PRINT_AND_GOTO(error); } // Set generator, order and cofactor bn[GX] = AndroidCryptoNative_BigNumFromBinary(gx, gxLength); bn[GY] = AndroidCryptoNative_BigNumFromBinary(gy, gyLength); loc[G] = (*env)->NewObject(env, g_ECPointClass, g_ECPointCtor, bn[GX], bn[GY]); + ON_EXCEPTION_PRINT_AND_GOTO(error); bn[ORDER] = AndroidCryptoNative_BigNumFromBinary(order, orderLength); @@ -514,6 +554,7 @@ EC_KEY* AndroidCryptoNative_EcKeyCreateByExplicitParameters(ECCurveType curveTyp } loc[paramSpec] = (*env)->NewObject(env, g_ECParameterSpecClass, g_ECParameterSpecCtor, loc[group], loc[G], bn[ORDER], cofactorInt); + ON_EXCEPTION_PRINT_AND_GOTO(error); if ((qx && qy) || d) { @@ -523,18 +564,14 @@ EC_KEY* AndroidCryptoNative_EcKeyCreateByExplicitParameters(ECCurveType curveTyp else { // Otherwise generate a new key pair. - jstring ec = make_java_string(env, "EC"); - jobject keyPairGenerator = - (*env)->CallStaticObjectMethod(env, g_keyPairGenClass, g_keyPairGenGetInstanceMethod, ec); - (*env)->CallVoidMethod(env, keyPairGenerator, g_keyPairGenInitializeWithParamsMethod, loc[paramSpec]); - if (CheckJNIExceptions(env)) - { - ReleaseLRef(env, keyPairGenerator); - ReleaseLRef(env, ec); - goto error; - } + loc[ec] = make_java_string(env, "EC"); + loc[keyPairGenerator] = + (*env)->CallStaticObjectMethod(env, g_keyPairGenClass, g_keyPairGenGetInstanceMethod, loc[ec]); + ON_EXCEPTION_PRINT_AND_GOTO(error); + (*env)->CallVoidMethod(env, loc[keyPairGenerator], g_keyPairGenInitializeWithParamsMethod, loc[paramSpec]); + ON_EXCEPTION_PRINT_AND_GOTO(error); - keyPair = AddGRef(env, (*env)->CallObjectMethod(env, keyPairGenerator, g_keyPairGenGenKeyPairMethod)); + keyPair = AddGRef(env, (*env)->CallObjectMethod(env, loc[keyPairGenerator], g_keyPairGenGenKeyPairMethod)); } if (!keyPair) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecdh.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecdh.c index 911975077b8647..457160c941d185 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecdh.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ecdh.c @@ -14,53 +14,42 @@ int32_t AndroidCryptoNative_EcdhDeriveKey(EC_KEY* ourKey, EC_KEY* peerKey, uint8 abort_if_invalid_pointer_argument (usedBufferLength); JNIEnv* env = GetJNIEnv(); + int32_t ret = FAIL; + *usedBufferLength = 0; - jstring algorithmName = make_java_string(env, "ECDH"); + INIT_LOCALS(loc, algorithmName, keyAgreement, privateKey, peerPublicKey, secret); - jobject keyAgreement = (*env)->CallStaticObjectMethod(env, g_KeyAgreementClass, g_KeyAgreementGetInstance, algorithmName); - ReleaseLRef(env, algorithmName); + loc[algorithmName] = make_java_string(env, "ECDH"); - jobject privateKey = (*env)->CallObjectMethod(env, ourKey->keyPair, g_keyPairGetPrivateMethod); + loc[keyAgreement] = (*env)->CallStaticObjectMethod(env, g_KeyAgreementClass, g_KeyAgreementGetInstance, loc[algorithmName]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - (*env)->CallVoidMethod(env, keyAgreement, g_KeyAgreementInit, privateKey); - ReleaseLRef(env, privateKey); - if (CheckJNIExceptions(env)) - { - ReleaseLRef(env, keyAgreement); - *usedBufferLength = 0; - return FAIL; - } + loc[privateKey] = (*env)->CallObjectMethod(env, ourKey->keyPair, g_keyPairGetPrivateMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jobject peerPublicKey = (*env)->CallObjectMethod(env, peerKey->keyPair, g_keyPairGetPublicMethod); - ReleaseLRef(env, (*env)->CallObjectMethod(env, keyAgreement, g_KeyAgreementDoPhase, peerPublicKey, JNI_TRUE)); - ReleaseLRef(env, peerPublicKey); - if (CheckJNIExceptions(env)) - { - ReleaseLRef(env, keyAgreement); - *usedBufferLength = 0; - return FAIL; - } + (*env)->CallVoidMethod(env, loc[keyAgreement], g_KeyAgreementInit, loc[privateKey]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jbyteArray secret = (*env)->CallObjectMethod(env, keyAgreement, g_KeyAgreementGenerateSecret); - ReleaseLRef(env, keyAgreement); + loc[peerPublicKey] = (*env)->CallObjectMethod(env, peerKey->keyPair, g_keyPairGetPublicMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + ReleaseLRef(env, (*env)->CallObjectMethod(env, loc[keyAgreement], g_KeyAgreementDoPhase, loc[peerPublicKey], JNI_TRUE)); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - if (CheckJNIExceptions(env)) - { - *usedBufferLength = 0; - return FAIL; - } + loc[secret] = (*env)->CallObjectMethod(env, loc[keyAgreement], g_KeyAgreementGenerateSecret); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - jsize secretBufferLen = (*env)->GetArrayLength(env, secret); + jsize secretBufferLen = (*env)->GetArrayLength(env, loc[secret]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); if (secretBufferLen > bufferLength) - { - ReleaseLRef(env, secret); - *usedBufferLength = 0; - return FAIL; - } + goto cleanup; - (*env)->GetByteArrayRegion(env, secret, 0, secretBufferLen, (jbyte*)resultKey); - ReleaseLRef(env, secret); + (*env)->GetByteArrayRegion(env, loc[secret], 0, secretBufferLen, (jbyte*)resultKey); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); *usedBufferLength = secretBufferLen; - return CheckJNIExceptions(env) ? FAIL : SUCCESS; + ret = SUCCESS; + +cleanup: + RELEASE_LOCALS(loc, env); + return ret; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_eckey.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_eckey.c index 765d31f9b419bf..d0002edc6edb52 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_eckey.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_eckey.c @@ -153,14 +153,25 @@ int32_t AndroidCryptoNative_EcKeyGetSize(const EC_KEY* key, int32_t* keySize) return FAIL; JNIEnv* env = GetJNIEnv(); - - jobject curve = (*env)->CallObjectMethod(env, key->curveParameters, g_ECParameterSpecGetCurve); - jobject field = (*env)->CallObjectMethod(env, curve, g_EllipticCurveGetField); - *keySize = (*env)->CallIntMethod(env, field, g_ECFieldGetFieldSize); - + int32_t ret = FAIL; + int32_t size = 0; + jobject curve = NULL; + jobject field = NULL; + + curve = (*env)->CallObjectMethod(env, key->curveParameters, g_ECParameterSpecGetCurve); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + field = (*env)->CallObjectMethod(env, curve, g_EllipticCurveGetField); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + size = (*env)->CallIntMethod(env, field, g_ECFieldGetFieldSize); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + *keySize = size; + ret = SUCCESS; + +cleanup: ReleaseLRef(env, field); ReleaseLRef(env, curve); - return SUCCESS; + return ret; } int32_t AndroidCryptoNative_EcKeyGetCurveName(const EC_KEY* key, uint16_t** curveName) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_hmac.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_hmac.c index a367d567771829..a769b79b6b4688 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_hmac.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_hmac.c @@ -15,27 +15,28 @@ jobject CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t type) // mac.init(key); JNIEnv* env = GetJNIEnv(); + jobject macObj = NULL; + bool success = false; + + INIT_LOCALS(loc, macName, keyBytes, sksObj); - jstring macName = NULL; if (type == CryptoNative_EvpSha1()) - macName = make_java_string(env, "HmacSHA1"); + loc[macName] = make_java_string(env, "HmacSHA1"); else if (type == CryptoNative_EvpSha256()) - macName = make_java_string(env, "HmacSHA256"); + loc[macName] = make_java_string(env, "HmacSHA256"); else if (type == CryptoNative_EvpSha384()) - macName = make_java_string(env, "HmacSHA384"); + loc[macName] = make_java_string(env, "HmacSHA384"); else if (type == CryptoNative_EvpSha512()) - macName = make_java_string(env, "HmacSHA512"); + loc[macName] = make_java_string(env, "HmacSHA512"); else if (type == CryptoNative_EvpMd5()) - macName = make_java_string(env, "HmacMD5"); + loc[macName] = make_java_string(env, "HmacMD5"); else - return FAIL; - - jbyteArray keyBytes; + goto cleanup; if (key && keyLen > 0) { - keyBytes = make_java_byte_array(env, keyLen); - (*env)->SetByteArrayRegion(env, keyBytes, 0, keyLen, (jbyte*)key); + loc[keyBytes] = make_java_byte_array(env, keyLen); + (*env)->SetByteArrayRegion(env, loc[keyBytes], 0, keyLen, (jbyte*)key); } else { @@ -43,30 +44,33 @@ jobject CryptoNative_HmacCreate(uint8_t* key, int32_t keyLen, intptr_t type) // so instead create an empty 1-byte length byte array that's initialized to 0. // the HMAC algorithm pads keys with zeros until the key is block-length, // so this effectively creates the same key as if it were a zero byte-length key. - keyBytes = make_java_byte_array(env, 1); + loc[keyBytes] = make_java_byte_array(env, 1); } - jobject sksObj = (*env)->NewObject(env, g_sksClass, g_sksCtor, keyBytes, macName); - if (CheckJNIExceptions(env) || sksObj == NULL) + loc[sksObj] = (*env)->NewObject(env, g_sksClass, g_sksCtor, loc[keyBytes], loc[macName]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (loc[sksObj] == NULL) { - if(sksObj == NULL) - { - LOG_WARN ("Unable to create an instance of SecretKeySpec"); - } - - (*env)->DeleteLocalRef(env, keyBytes); - (*env)->DeleteLocalRef(env, sksObj); - (*env)->DeleteLocalRef(env, macName); - return FAIL; + LOG_WARN ("Unable to create an instance of SecretKeySpec"); + goto cleanup; } - jobject macObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_MacClass, g_MacGetInstance, macName)); - (*env)->CallVoidMethod(env, macObj, g_MacInit, sksObj); - (*env)->DeleteLocalRef(env, keyBytes); - (*env)->DeleteLocalRef(env, sksObj); - (*env)->DeleteLocalRef(env, macName); + macObj = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_MacClass, g_MacGetInstance, loc[macName])); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); - return CheckJNIExceptions(env) ? FAIL : macObj; + (*env)->CallVoidMethod(env, macObj, g_MacInit, loc[sksObj]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + success = true; + +cleanup: + RELEASE_LOCALS(loc, env); + if (!success) + { + ReleaseGRef(env, macObj); + return FAIL; + } + return macObj; } int32_t CryptoNative_HmacReset(jobject ctx) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ssl.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ssl.c index 29571dd0289bad..0b581e9b4e2f49 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_ssl.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_ssl.c @@ -8,22 +8,38 @@ PAL_SslProtocol AndroidCryptoNative_SSLGetSupportedProtocols(void) JNIEnv* env = GetJNIEnv(); PAL_SslProtocol supported = 0; INIT_LOCALS(loc, context, params, protocols); + jstring protocol = NULL; + const char* protocolStr = NULL; // SSLContext context = SSLContext.getDefault(); // SSLParameters params = context.getDefaultSSLParameters(); // String[] protocols = params.getProtocols(); loc[context] = (*env)->CallStaticObjectMethod(env, g_sslCtxClass, g_sslCtxGetDefaultMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); loc[params] = (*env)->CallObjectMethod(env, loc[context], g_sslCtxGetDefaultSslParamsMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); loc[protocols] = (*env)->CallObjectMethod(env, loc[params], g_SSLParametersGetProtocols); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); const char tlsv1[] = "TLSv1"; size_t tlsv1Len = (sizeof(tlsv1) / sizeof(*tlsv1)) - 1; jsize count = (*env)->GetArrayLength(env, loc[protocols]); + ON_EXCEPTION_PRINT_AND_GOTO(error); for (int32_t i = 0; i < count; i++) { - jstring protocol = (*env)->GetObjectArrayElement(env, loc[protocols], i); - const char* protocolStr = (*env)->GetStringUTFChars(env, protocol, NULL); + protocol = (*env)->GetObjectArrayElement(env, loc[protocols], i); + ON_EXCEPTION_PRINT_AND_GOTO(error); + if (protocol == NULL) + goto error; + + protocolStr = (*env)->GetStringUTFChars(env, protocol, NULL); + if (protocolStr == NULL) + { + ON_EXCEPTION_PRINT_AND_GOTO(error); + goto error; + } + if (strncmp(protocolStr, tlsv1, tlsv1Len) == 0) { if (strlen(protocolStr) == tlsv1Len) @@ -45,9 +61,21 @@ PAL_SslProtocol AndroidCryptoNative_SSLGetSupportedProtocols(void) } (*env)->ReleaseStringUTFChars(env, protocol, protocolStr); - (*env)->DeleteLocalRef(env, protocol); + protocolStr = NULL; + ReleaseLRef(env, protocol); + protocol = NULL; } + goto cleanup; + +error: + supported = 0; + +cleanup: + if (protocolStr != NULL) + (*env)->ReleaseStringUTFChars(env, protocol, protocolStr); + + ReleaseLRef(env, protocol); RELEASE_LOCALS(loc, env); return supported; } diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c index c45e12b1319d6e..c90458d0bafb29 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_sslstream.c @@ -38,12 +38,22 @@ ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoUnwrap(JNIEnv* env, SSLStream* ss ARGS_NON_NULL_ALL static int GetHandshakeStatus(JNIEnv* env, SSLStream* sslStream) { + int ret = -1; + INIT_LOCALS(loc, status); + // int handshakeStatus = sslEngine.getHandshakeStatus().ordinal(); - int handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetHandshakeStatus)); - if (CheckJNIExceptions(env)) - return -1; + loc[status] = (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetHandshakeStatus); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (loc[status] == NULL) + goto cleanup; - return handshakeStatus; + int handshakeStatus = GetEnumAsInt(env, loc[status]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + ret = handshakeStatus; + +cleanup: + RELEASE_LOCALS(loc, env); + return ret; } static bool IsHandshaking(int handshakeStatus) @@ -79,6 +89,8 @@ ARGS_NON_NULL_ALL static PAL_SSLStreamStatus Close(JNIEnv* env, SSLStream* sslSt // sslEngine.closeOutbound(); (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineCloseOutbound); + if (CheckJNIExceptions(env)) + return SSLStreamStatus_Error; if (ret != SSLStreamStatus_OK) return ret; @@ -126,9 +138,21 @@ ARGS_NON_NULL_ALL static jobject ExpandBuffer(JNIEnv* env, jobject oldBuffer, in // ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); // newBuffer.put(oldBuffer); IGNORE_RETURN((*env)->CallObjectMethod(env, oldBuffer, g_ByteBufferFlip)); + if (CheckJNIExceptions(env)) + return NULL; + jobject newBuffer = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_ByteBuffer, g_ByteBufferAllocate, newCapacity)); + if (CheckJNIExceptions(env) || newBuffer == NULL) + return NULL; + IGNORE_RETURN((*env)->CallObjectMethod(env, newBuffer, g_ByteBufferPutBuffer, oldBuffer)); + if (CheckJNIExceptions(env)) + { + ReleaseGRef(env, newBuffer); + return NULL; + } + ReleaseGRef(env, oldBuffer); return newBuffer; } @@ -136,8 +160,17 @@ ARGS_NON_NULL_ALL static jobject ExpandBuffer(JNIEnv* env, jobject oldBuffer, in ARGS_NON_NULL_ALL static jobject EnsureRemaining(JNIEnv* env, jobject oldBuffer, int32_t newRemaining) { IGNORE_RETURN((*env)->CallObjectMethod(env, oldBuffer, g_ByteBufferCompact)); + if (CheckJNIExceptions(env)) + return NULL; + int32_t oldPosition = (*env)->CallIntMethod(env, oldBuffer, g_ByteBufferPosition); + if (CheckJNIExceptions(env)) + return NULL; + int32_t oldRemaining = (*env)->CallIntMethod(env, oldBuffer, g_ByteBufferRemaining); + if (CheckJNIExceptions(env)) + return NULL; + if (oldRemaining < newRemaining) { // After compacting the oldBuffer, the oldPosition is equal to the number of bytes in the buffer at the moment @@ -152,52 +185,91 @@ ARGS_NON_NULL_ALL static jobject EnsureRemaining(JNIEnv* env, jobject oldBuffer, ARGS_NON_NULL_ALL static PAL_SSLStreamStatus WrapAndProcessResult(JNIEnv* env, SSLStream* sslStream, int* handshakeStatus, int* bytesConsumed, bool* repeat) { + PAL_SSLStreamStatus ret = SSLStreamStatus_Error; + jobject resultHandshakeStatus = NULL; + jobject resultStatus = NULL; + // SSLEngineResult result = sslEngine.wrap(appOutBuffer, netOutBuffer); jobject result = (*env)->CallObjectMethod( env, sslStream->sslEngine, g_SSLEngineWrap, sslStream->appOutBuffer, sslStream->netOutBuffer); - if (CheckJNIExceptions(env)) - return SSLStreamStatus_Error; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (result == NULL) + goto cleanup; // handshakeStatus = result.getHandshakeStatus(); // bytesConsumed = result.bytesConsumed(); // SSLEngineResult.Status status = result.getStatus(); - *handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetHandshakeStatus)); + resultHandshakeStatus = (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetHandshakeStatus); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (resultHandshakeStatus == NULL) + goto cleanup; + + *handshakeStatus = GetEnumAsInt(env, resultHandshakeStatus); + resultHandshakeStatus = NULL; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + *bytesConsumed = (*env)->CallIntMethod(env, result, g_SSLEngineResultBytesConsumed); - int status = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus)); - (*env)->DeleteLocalRef(env, result); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + resultStatus = (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (resultStatus == NULL) + goto cleanup; + + int status = GetEnumAsInt(env, resultStatus); + resultStatus = NULL; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); switch (status) { case STATUS__OK: { - return Flush(env, sslStream); + ret = Flush(env, sslStream); + break; } case STATUS__CLOSED: { (void)Flush(env, sslStream); (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineCloseOutbound); - return SSLStreamStatus_Closed; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + ret = SSLStreamStatus_Closed; + break; } case STATUS__BUFFER_OVERFLOW: { // Expand buffer and repeat the wrap int32_t packetBufferSize = (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetPacketBufferSize); - sslStream->netOutBuffer = ExpandBuffer(env, sslStream->netOutBuffer, packetBufferSize); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + jobject netOutBuffer = ExpandBuffer(env, sslStream->netOutBuffer, packetBufferSize); + if (netOutBuffer == NULL) + goto cleanup; + + sslStream->netOutBuffer = netOutBuffer; *repeat = true; - return SSLStreamStatus_OK; + ret = SSLStreamStatus_OK; + break; } default: { LOG_ERROR("Unknown SSLEngineResult status: %d", status); - return SSLStreamStatus_Error; + break; } } + +cleanup: + ReleaseLRef(env, resultHandshakeStatus); + ReleaseLRef(env, resultStatus); + ReleaseLRef(env, result); + return ret; } ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoWrap(JNIEnv* env, SSLStream* sslStream, int* handshakeStatus, int* bytesConsumed) { // appOutBuffer.flip(); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->appOutBuffer, g_ByteBufferFlip)); + if (CheckJNIExceptions(env)) + return SSLStreamStatus_Error; bool repeat = false; PAL_SSLStreamStatus status = WrapAndProcessResult(env, sslStream, handshakeStatus, bytesConsumed, &repeat); @@ -216,93 +288,151 @@ ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoWrap(JNIEnv* env, SSLStream* sslS // appOutBuffer.compact(); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->appOutBuffer, g_ByteBufferCompact)); + if (CheckJNIExceptions(env)) + return SSLStreamStatus_Error; return status; } ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoUnwrap(JNIEnv* env, SSLStream* sslStream, int* handshakeStatus) { + PAL_SSLStreamStatus ret = SSLStreamStatus_Error; + uint8_t* tmpNative = NULL; + jobject tmp = NULL; + jobject result = NULL; + jobject resultHandshakeStatus = NULL; + jobject resultStatus = NULL; + // if (netInBuffer.position() == 0) // { // int netInBufferLimit = netInBuffer.limit(); - // ByteBuffer tmp = ByteBuffer.allocateDirect(netInBufferLimit); - // int count = streamReader(tmp, 0, netInBufferLimit); + // byte[] tmpNative = new byte[netInBufferLimit]; + // // ... fill tmpNative from the stream + // ByteBuffer tmp = ByteBuffer.allocateDirect(count); // netInBuffer.put(tmp); // } - if ((*env)->CallIntMethod(env, sslStream->netInBuffer, g_ByteBufferPosition) == 0) + int position = (*env)->CallIntMethod(env, sslStream->netInBuffer, g_ByteBufferPosition); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + if (position == 0) { + // int netInBufferLimit = netInBuffer.limit(); int netInBufferLimit = (*env)->CallIntMethod(env, sslStream->netInBuffer, g_ByteBufferLimit); - uint8_t* tmpNative = (uint8_t*)xmalloc((size_t)netInBufferLimit); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + tmpNative = (uint8_t*)xmalloc((size_t)netInBufferLimit); int count = netInBufferLimit; // todo assert streamReader != 0 ? PAL_SSLStreamStatus status = sslStream->streamReader(sslStream->managedContextHandle, tmpNative, &count); if (status != SSLStreamStatus_OK) { - free(tmpNative); - return status; + ret = status; + goto cleanup; } - jobject tmp = (*env)->NewDirectByteBuffer(env, tmpNative, count); + // ByteBuffer tmp = ByteBuffer.allocateDirect(count); + tmp = (*env)->NewDirectByteBuffer(env, tmpNative, count); ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + // netInBuffer.put(tmp); IGNORE_RETURN( (*env)->CallObjectMethod(env, sslStream->netInBuffer, g_ByteBufferPutBuffer, tmp)); -cleanup: - free(tmpNative); - (*env)->DeleteLocalRef(env, tmp); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); } // netInBuffer.flip(); // SSLEngineResult result = sslEngine.unwrap(netInBuffer, appInBuffer); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->netInBuffer, g_ByteBufferFlip)); - jobject result = (*env)->CallObjectMethod( + result = (*env)->CallObjectMethod( env, sslStream->sslEngine, g_SSLEngineUnwrap, sslStream->netInBuffer, sslStream->appInBuffer); - if (CheckJNIExceptions(env)) - return SSLStreamStatus_Error; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (result == NULL) + goto cleanup; // netInBuffer.compact(); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->netInBuffer, g_ByteBufferCompact)); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); // handshakeStatus = result.getHandshakeStatus(); // SSLEngineResult.Status status = result.getStatus(); - *handshakeStatus = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetHandshakeStatus)); - int status = GetEnumAsInt(env, (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus)); - (*env)->DeleteLocalRef(env, result); + resultHandshakeStatus = (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetHandshakeStatus); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (resultHandshakeStatus == NULL) + goto cleanup; + + *handshakeStatus = GetEnumAsInt(env, resultHandshakeStatus); + resultHandshakeStatus = NULL; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + resultStatus = (*env)->CallObjectMethod(env, result, g_SSLEngineResultGetStatus); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (resultStatus == NULL) + goto cleanup; + + int status = GetEnumAsInt(env, resultStatus); + resultStatus = NULL; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); switch (status) { case STATUS__OK: { - return SSLStreamStatus_OK; + ret = SSLStreamStatus_OK; + break; } case STATUS__CLOSED: { - return Close(env, sslStream); + ret = Close(env, sslStream); + break; } case STATUS__BUFFER_UNDERFLOW: { // Expand buffer // int newRemaining = sslSession.getPacketBufferSize(); int32_t newRemaining = (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetPacketBufferSize); - sslStream->netInBuffer = EnsureRemaining(env, sslStream->netInBuffer, newRemaining); - return SSLStreamStatus_OK; + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + jobject netInBuffer = EnsureRemaining(env, sslStream->netInBuffer, newRemaining); + if (netInBuffer == NULL) + goto cleanup; + + sslStream->netInBuffer = netInBuffer; + ret = SSLStreamStatus_OK; + break; } case STATUS__BUFFER_OVERFLOW: { // Expand buffer // int newCapacity = sslSession.getApplicationBufferSize() + appInBuffer.remaining(); - int32_t newCapacity = - (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetApplicationBufferSize) + - (*env)->CallIntMethod(env, sslStream->appInBuffer, g_ByteBufferRemaining); - sslStream->appInBuffer = ExpandBuffer(env, sslStream->appInBuffer, newCapacity); - return SSLStreamStatus_OK; + int32_t applicationBufferSize = + (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetApplicationBufferSize); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + int32_t appInBufferRemaining = (*env)->CallIntMethod(env, sslStream->appInBuffer, g_ByteBufferRemaining); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + + jobject appInBuffer = ExpandBuffer(env, sslStream->appInBuffer, applicationBufferSize + appInBufferRemaining); + if (appInBuffer == NULL) + goto cleanup; + + sslStream->appInBuffer = appInBuffer; + ret = SSLStreamStatus_OK; + break; } default: { LOG_ERROR("Unknown SSLEngineResult status: %d", status); - return SSLStreamStatus_Error; + break; } } + +cleanup: + free(tmpNative); + ReleaseLRef(env, tmp); + ReleaseLRef(env, resultHandshakeStatus); + ReleaseLRef(env, resultStatus); + ReleaseLRef(env, result); + return ret; } ARGS_NON_NULL_ALL static PAL_SSLStreamStatus DoHandshake(JNIEnv* env, SSLStream* sslStream) @@ -344,7 +474,11 @@ ARGS_NON_NULL_ALL static void FreeSSLStream(JNIEnv* env, SSLStream* sslStream) ReleaseGRef(env, sslStream->netInBuffer); ReleaseGRef(env, sslStream->appInBuffer); - sslStream->managedContextCleanup(sslStream->managedContextHandle); + // managedContextCleanup may be NULL if the SSLStream was created but + // SSLStreamInitialize was never called. In that case there is no managed + // handle to release. + if (sslStream->managedContextCleanup != NULL) + sslStream->managedContextCleanup(sslStream->managedContextHandle); free(sslStream); } @@ -445,6 +579,7 @@ static int32_t AddCertChainToStore(JNIEnv* env, loc[keyBytes] = make_java_byte_array(env, pkcs8PrivateKeyLen); (*env)->SetByteArrayRegion(env, loc[keyBytes], 0, pkcs8PrivateKeyLen, (jbyte*)pkcs8PrivateKey); loc[keySpec] = (*env)->NewObject(env, g_PKCS8EncodedKeySpec, g_PKCS8EncodedKeySpecCtor, loc[keyBytes]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); switch (algorithm) { @@ -466,7 +601,9 @@ static int32_t AddCertChainToStore(JNIEnv* env, // PrivateKey privateKey = keyFactory.generatePrivate(spec); loc[keyFactory] = (*env)->CallStaticObjectMethod(env, g_KeyFactoryClass, g_KeyFactoryGetInstanceMethod, loc[algorithmName]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); loc[privateKey] = (*env)->CallObjectMethod(env, loc[keyFactory], g_KeyFactoryGenPrivateMethod, loc[keySpec]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); // X509Certificate[] certArray = new X509Certificate[certsLen]; loc[certArray] = make_java_object_array(env, certsLen, g_X509CertClass, NULL); @@ -592,6 +729,11 @@ int32_t AndroidCryptoNative_SSLStreamInitialize( abort_unless(sslStream->sslEngine == NULL, "sslEngine is NOT NULL in SSL stream"); abort_unless(sslStream->sslSession == NULL, "sslSession is NOT NULL in SSL stream"); + sslStream->managedContextHandle = managedContextHandle; + sslStream->streamReader = streamReader; + sslStream->streamWriter = streamWriter; + sslStream->managedContextCleanup = managedContextCleanup; + int32_t ret = FAIL; JNIEnv* env = GetJNIEnv(); @@ -613,16 +755,23 @@ int32_t AndroidCryptoNative_SSLStreamInitialize( // sslEngine.setUseClientMode(!isServer); sslStream->sslEngine = ToGRef(env, sslEngine); + ON_EXCEPTION_PRINT_AND_GOTO(exit); + if (sslStream->sslEngine == NULL) + goto exit; + (*env)->CallVoidMethod(env, sslStream->sslEngine, g_SSLEngineSetUseClientMode, !isServer); ON_EXCEPTION_PRINT_AND_GOTO(exit); // SSLSession sslSession = sslEngine.getSession(); sslStream->sslSession = ToGRef(env, (*env)->CallObjectMethod(env, sslStream->sslEngine, g_SSLEngineGetSession)); + ON_EXCEPTION_PRINT_AND_GOTO(exit); // int applicationBufferSize = sslSession.getApplicationBufferSize(); // int packetBufferSize = sslSession.getPacketBufferSize(); int32_t applicationBufferSize = (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetApplicationBufferSize); + ON_EXCEPTION_PRINT_AND_GOTO(exit); int32_t packetBufferSize = (*env)->CallIntMethod(env, sslStream->sslSession, g_SSLSessionGetPacketBufferSize); + ON_EXCEPTION_PRINT_AND_GOTO(exit); // ByteBuffer appInBuffer = ByteBuffer.allocate(Math.max(applicationBufferSize, appBufferSize)); // ByteBuffer appOutBuffer = ByteBuffer.allocate(appBufferSize); @@ -631,17 +780,16 @@ int32_t AndroidCryptoNative_SSLStreamInitialize( int32_t appInBufferSize = applicationBufferSize > appBufferSize ? applicationBufferSize : appBufferSize; sslStream->appInBuffer = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_ByteBuffer, g_ByteBufferAllocate, appInBufferSize)); + ON_EXCEPTION_PRINT_AND_GOTO(exit); sslStream->appOutBuffer = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_ByteBuffer, g_ByteBufferAllocate, appBufferSize)); + ON_EXCEPTION_PRINT_AND_GOTO(exit); sslStream->netOutBuffer = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_ByteBuffer, g_ByteBufferAllocate, packetBufferSize)); + ON_EXCEPTION_PRINT_AND_GOTO(exit); sslStream->netInBuffer = ToGRef(env, (*env)->CallStaticObjectMethod(env, g_ByteBuffer, g_ByteBufferAllocate, packetBufferSize)); - - sslStream->managedContextHandle = managedContextHandle; - sslStream->streamReader = streamReader; - sslStream->streamWriter = streamWriter; - sslStream->managedContextCleanup = managedContextCleanup; + ON_EXCEPTION_PRINT_AND_GOTO(exit); ret = SUCCESS; @@ -795,6 +943,7 @@ PAL_SSLStreamStatus AndroidCryptoNative_SSLStreamWrite(SSLStream* sslStream, uin // appOutBuffer = EnsureRemaining(appOutBuffer, length); // appOutBuffer.put(bufferByteBuffer); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->appOutBuffer, g_ByteBufferCompact)); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); sslStream->appOutBuffer = EnsureRemaining(env, sslStream->appOutBuffer, length); IGNORE_RETURN((*env)->CallObjectMethod(env, sslStream->appOutBuffer, g_ByteBufferPutBuffer, bufferByteBuffer)); ON_EXCEPTION_PRINT_AND_GOTO(cleanup); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509.c index 99c6e522a203c6..f9c0b50505179a 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509.c @@ -101,6 +101,7 @@ int32_t AndroidCryptoNative_X509DecodeCollection(const uint8_t* buf, ON_EXCEPTION_PRINT_AND_GOTO(cleanup); jint certCount = (*env)->CallIntMethod(env, loc[certs], g_CollectionSize); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); bool insufficientBuffer = *outLen < certCount; *outLen = certCount; @@ -164,6 +165,7 @@ int32_t AndroidCryptoNative_X509ExportPkcs7(jobject* /*X509Certificate[]*/ certs // foreach (Certificate cert in certs) // certList.add(cert); loc[certList] = (*env)->NewObject(env, g_ArrayListClass, g_ArrayListCtorWithCapacity, certsLen); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); for (int i = 0; i < certsLen; ++i) { (*env)->CallBooleanMethod(env, loc[certList], g_ArrayListAdd, certs[i]); diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509store.c b/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509store.c index 83ef030694ba70..703546684d8d41 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509store.c +++ b/src/native/libs/System.Security.Cryptography.Native.Android/pal_x509store.c @@ -18,21 +18,29 @@ typedef enum EntryFlags_MatchesCertificate = 4, } EntryFlags; -// Returns whether or not the store contains the specified alias -// If the entry exists, the flags parameter is set based on the contents of the entry -ARGS_NON_NULL_ALL static bool ContainsEntryForAlias( - JNIEnv* env, jobject /*KeyStore*/ store, jobject /*X509Certificate*/ cert, jstring alias, EntryFlags* flags) +// Determines whether the store contains the specified alias, populating *flags +// with the entry's contents when present. +// Returns SUCCESS if the lookup completed (regardless of whether an entry exists), +// FAIL if a JNI exception was encountered while inspecting the store entry. +// On SUCCESS, *contains indicates whether an entry exists for the alias. +ARGS_NON_NULL_ALL static int32_t ContainsEntryForAlias( + JNIEnv* env, jobject /*KeyStore*/ store, jobject /*X509Certificate*/ cert, jstring alias, bool* contains, EntryFlags* flags) { - bool ret = false; + int32_t ret = FAIL; EntryFlags flagsLocal = EntryFlags_None; + bool containsLocal = false; INIT_LOCALS(loc, entry, existingCert); bool containsAlias = (*env)->CallBooleanMethod(env, store, g_KeyStoreContainsAlias, alias); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); if (!containsAlias) + { + ret = SUCCESS; goto cleanup; + } - ret = true; + containsLocal = true; // KeyStore.Entry entry = store.getEntry(alias, null); // if (entry instanceof KeyStore.PrivateKeyEntry) { @@ -48,42 +56,65 @@ ARGS_NON_NULL_ALL static bool ContainsEntryForAlias( flagsLocal |= EntryFlags_HasCertificate; flagsLocal |= EntryFlags_HasPrivateKey; loc[existingCert] = (*env)->CallObjectMethod(env, loc[entry], g_PrivateKeyEntryGetCertificate); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); } else if ((*env)->IsInstanceOf(env, loc[entry], g_TrustedCertificateEntryClass)) { flagsLocal |= EntryFlags_HasCertificate; loc[existingCert] = (*env)->CallObjectMethod(env, loc[entry], g_TrustedCertificateEntryGetTrustedCertificate); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); } else { // Entry for alias exists, but doesn't represent a certificate or private key + certificate + ret = SUCCESS; goto cleanup; } assert(loc[existingCert] != NULL); - if ((*env)->CallBooleanMethod(env, cert, g_X509CertEquals, loc[existingCert])) + jboolean equals = (*env)->CallBooleanMethod(env, cert, g_X509CertEquals, loc[existingCert]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); + if (equals) { flagsLocal |= EntryFlags_MatchesCertificate; } + ret = SUCCESS; + cleanup: RELEASE_LOCALS(loc, env); - *flags = flagsLocal; + if (ret == SUCCESS) + { + *contains = containsLocal; + *flags = flagsLocal; + } return ret; } +// Determines whether the store contains the specified alias with a matching certificate. +// Returns SUCCESS if the lookup completed (regardless of match result), FAIL on a JNI +// exception while inspecting the entry. On SUCCESS, *matches indicates whether the entry +// exists AND its certificate matches the supplied cert. ARGS_NON_NULL_ALL -static bool ContainsMatchingCertificateForAlias(JNIEnv* env, - jobject /*KeyStore*/ store, - jobject /*X509Certificate*/ cert, - jstring alias) +static int32_t ContainsMatchingCertificateForAlias(JNIEnv* env, + jobject /*KeyStore*/ store, + jobject /*X509Certificate*/ cert, + jstring alias, + bool* matches) { EntryFlags flags; - if (!ContainsEntryForAlias(env, store, cert, alias, &flags)) - return false; + bool contains = false; + *matches = false; + + if (ContainsEntryForAlias(env, store, cert, alias, &contains, &flags) != SUCCESS) + return FAIL; + + if (!contains) + return SUCCESS; EntryFlags matchesFlags = EntryFlags_HasCertificate & EntryFlags_MatchesCertificate; - return (flags & matchesFlags) == matchesFlags; + *matches = (flags & matchesFlags) == matchesFlags; + return SUCCESS; } int32_t AndroidCryptoNative_X509StoreAddCertificate(jobject /*KeyStore*/ store, @@ -98,7 +129,13 @@ int32_t AndroidCryptoNative_X509StoreAddCertificate(jobject /*KeyStore*/ store, jstring alias = make_java_string(env, hashString); EntryFlags flags; - if (ContainsEntryForAlias(env, store, cert, alias, &flags)) + bool contains = false; + if (ContainsEntryForAlias(env, store, cert, alias, &contains, &flags) != SUCCESS) + { + ReleaseLRef(env, alias); + return FAIL; + } + if (contains) { ReleaseLRef(env, alias); EntryFlags matchesFlags = EntryFlags_HasCertificate & EntryFlags_MatchesCertificate; @@ -136,11 +173,15 @@ int32_t AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey(jobject /*KeyS INIT_LOCALS(loc, alias, certs); jobject privateKey = NULL; + bool releasePrivateKey = true; loc[alias] = make_java_string(env, hashString); EntryFlags flags; - if (ContainsEntryForAlias(env, store, cert, loc[alias], &flags)) + bool contains = false; + if (ContainsEntryForAlias(env, store, cert, loc[alias], &contains, &flags) != SUCCESS) + goto cleanup; + if (contains) { EntryFlags matchesFlags = EntryFlags_HasCertificate & EntryFlags_MatchesCertificate; if ((flags & matchesFlags) != matchesFlags) @@ -161,21 +202,23 @@ int32_t AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey(jobject /*KeyS // Delete existing entry. We will replace the existing cert with the cert + private key. // store.deleteEntry(alias); (*env)->CallVoidMethod(env, store, g_KeyStoreDeleteEntry, loc[alias]); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); } - bool releasePrivateKey = true; switch (algorithm) { case PAL_EC: { EC_KEY* ec = (EC_KEY*)key; privateKey = (*env)->CallObjectMethod(env, ec->keyPair, g_keyPairGetPrivateMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); break; } case PAL_DSA: { // key is a KeyPair jobject privateKey = (*env)->CallObjectMethod(env, key, g_keyPairGetPrivateMethod); + ON_EXCEPTION_PRINT_AND_GOTO(cleanup); break; } case PAL_RSA: @@ -205,7 +248,7 @@ int32_t AndroidCryptoNative_X509StoreAddCertificateWithPrivateKey(jobject /*KeyS RELEASE_LOCALS(loc, env); if (releasePrivateKey) { - (*env)->DeleteLocalRef(env, privateKey); + ReleaseLRef(env, privateKey); } return ret; @@ -222,7 +265,13 @@ bool AndroidCryptoNative_X509StoreContainsCertificate(jobject /*KeyStore*/ store JNIEnv* env = GetJNIEnv(); jstring alias = make_java_string(env, hashString); - bool containsCert = ContainsMatchingCertificateForAlias(env, store, cert, alias); + bool containsCert = false; + if (ContainsMatchingCertificateForAlias(env, store, cert, alias, &containsCert) != SUCCESS) + { + // Lookup failed (JNI exception). Treat as "not contained" so the exception + // doesn't leak back to managed code. + containsCert = false; + } (*env)->DeleteLocalRef(env, alias); return containsCert; } @@ -290,8 +339,11 @@ EnumerateCertificates(JNIEnv* env, jobject /*KeyStore*/ store, EnumCertificatesC // Public publicKey = cert.getPublicKey(); // PrivateKey privateKey = entry.getPrivateKey(); loc[cert] = (*env)->CallObjectMethod(env, loc[entry], g_PrivateKeyEntryGetCertificate); + ON_EXCEPTION_PRINT_AND_GOTO(loop_cleanup); loc[publicKey] = (*env)->CallObjectMethod(env, loc[cert], g_X509CertGetPublicKey); + ON_EXCEPTION_PRINT_AND_GOTO(loop_cleanup); loc[privateKey] = (*env)->CallObjectMethod(env, loc[entry], g_PrivateKeyEntryGetPrivateKey); + ON_EXCEPTION_PRINT_AND_GOTO(loop_cleanup); PAL_KeyAlgorithm keyAlgorithm = PAL_UnknownAlgorithm; void* keyHandle = HandleFromKeys(env, loc[publicKey], loc[privateKey], &keyAlgorithm); @@ -305,10 +357,13 @@ EnumerateCertificates(JNIEnv* env, jobject /*KeyStore*/ store, EnumCertificatesC { // Certificate cert = entry.getTrustedCertificate(); loc[cert] = (*env)->CallObjectMethod(env, loc[entry], g_TrustedCertificateEntryGetTrustedCertificate); + ON_EXCEPTION_PRINT_AND_GOTO(loop_cleanup); cb(AddGRef(env, loc[cert]), NULL /*privateKey*/, PAL_UnknownAlgorithm, context); } loop_cleanup: + // Per-entry exceptions have been logged and cleared via ON_EXCEPTION_PRINT_AND_GOTO. + // We silently skip the failed entry and continue, preserving the original behavior. RELEASE_LOCALS(loc, env); hasNext = (*env)->CallBooleanMethod(env, aliases, g_EnumerationHasMoreElements); @@ -340,6 +395,11 @@ static bool SystemAliasFilter(JNIEnv* env, jstring alias) size_t prefixLen = (sizeof(systemPrefix) / sizeof(*systemPrefix)) - 1; const char* aliasPtr = (*env)->GetStringUTFChars(env, alias, NULL); + if (aliasPtr == NULL) + { + TryClearJNIExceptions(env); + return false; + } bool isSystem = (strncmp(aliasPtr, systemPrefix, prefixLen) == 0); (*env)->ReleaseStringUTFChars(env, alias, aliasPtr); return isSystem; @@ -454,7 +514,10 @@ int32_t AndroidCryptoNative_X509StoreRemoveCertificate(jobject /*KeyStore*/ stor int32_t ret = FAIL; jstring alias = make_java_string(env, hashString); - if (!ContainsMatchingCertificateForAlias(env, store, cert, alias)) + bool containsCert = false; + if (ContainsMatchingCertificateForAlias(env, store, cert, alias, &containsCert) != SUCCESS) + goto cleanup; + if (!containsCert) { // Certificate is not in store - nothing to do ret = SUCCESS;