@@ -1233,6 +1233,273 @@ static jlong NativeCrypto_EVP_parse_private_key(JNIEnv* env, jclass, jbyteArray
12331233 return reinterpret_cast<uintptr_t>(pkey.release());
12341234}
12351235
1236+ static const EVP_PKEY_ALG* GetAlg(int pkeyType) {
1237+ switch (pkeyType) {
1238+ case EVP_PKEY_ED25519:
1239+ return EVP_pkey_ed25519();
1240+ case EVP_PKEY_X25519:
1241+ return EVP_pkey_x25519();
1242+ case EVP_PKEY_ML_DSA_65:
1243+ return EVP_pkey_ml_dsa_65();
1244+ case EVP_PKEY_ML_DSA_87:
1245+ return EVP_pkey_ml_dsa_87();
1246+ default:
1247+ return nullptr;
1248+ }
1249+ }
1250+
1251+ static jlong NativeCrypto_EVP_PKEY_from_private_key_info(JNIEnv* env, jclass,
1252+ jbyteArray key_java_bytes,
1253+ jintArray algs) {
1254+ CHECK_ERROR_QUEUE_ON_RETURN;
1255+ JNI_TRACE("EVP_PKEY_from_private_key_info(_, %p)", algs);
1256+
1257+ if (key_java_bytes == nullptr) {
1258+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
1259+ return 0;
1260+ }
1261+
1262+ ScopedByteArrayRO bytes(env, key_java_bytes);
1263+ if (bytes.get() == nullptr) {
1264+ JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
1265+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
1266+ return 0;
1267+ }
1268+
1269+ size_t num_algs = static_cast<size_t>(env->GetArrayLength(algs));
1270+ if (num_algs == 0) {
1271+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
1272+ "algs.length == 0");
1273+ return 0;
1274+ }
1275+ ScopedIntArrayRO algs_ro(env, algs);
1276+ std::vector<const EVP_PKEY_ALG*> alg_pointers(num_algs);
1277+ for (size_t i = 0; i < num_algs; ++i) {
1278+ const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
1279+ if (alg == nullptr) {
1280+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
1281+ "unsupported pkeyType");
1282+ return 0;
1283+ }
1284+ alg_pointers[i] = alg;
1285+ }
1286+
1287+ bssl::UniquePtr<EVP_PKEY> pkey(
1288+ EVP_PKEY_from_private_key_info(reinterpret_cast<const uint8_t*>(bytes.get()),
1289+ bytes.size(), alg_pointers.data(), alg_pointers.size()));
1290+ if (pkey.get() == nullptr) {
1291+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
1292+ ERR_clear_error();
1293+ JNI_TRACE("EVP_PKEY_from_private_key_info => threw exception");
1294+ return 0;
1295+ }
1296+
1297+ return reinterpret_cast<uintptr_t>(pkey.release());
1298+ }
1299+
1300+ static jlong NativeCrypto_EVP_PKEY_from_subject_public_key_info(JNIEnv* env, jclass,
1301+ jbyteArray key_java_bytes,
1302+ jintArray algs) {
1303+ CHECK_ERROR_QUEUE_ON_RETURN;
1304+ JNI_TRACE("EVP_PKEY_from_subject_public_key_info(%p, %p)", key_java_bytes, algs);
1305+
1306+ if (key_java_bytes == nullptr) {
1307+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
1308+ return 0;
1309+ }
1310+
1311+ ScopedByteArrayRO bytes(env, key_java_bytes);
1312+ if (bytes.get() == nullptr) {
1313+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
1314+ key_java_bytes);
1315+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for bytes");
1316+ return 0;
1317+ }
1318+
1319+ size_t num_algs = static_cast<size_t>(env->GetArrayLength(algs));
1320+ if (num_algs == 0) {
1321+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
1322+ "algs.length == 0");
1323+ return 0;
1324+ }
1325+ ScopedIntArrayRO algs_ro(env, algs);
1326+ std::vector<const EVP_PKEY_ALG*> alg_pointers(num_algs);
1327+ for (size_t i = 0; i < num_algs; ++i) {
1328+ const EVP_PKEY_ALG* alg = GetAlg(algs_ro.get()[i]);
1329+ if (alg == nullptr) {
1330+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
1331+ "unsupported pkeyType");
1332+ return 0;
1333+ }
1334+ alg_pointers[i] = alg;
1335+ }
1336+
1337+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_from_subject_public_key_info(
1338+ reinterpret_cast<const uint8_t*>(bytes.get()), bytes.size(), alg_pointers.data(),
1339+ alg_pointers.size()));
1340+ if (pkey.get() == nullptr) {
1341+ conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
1342+ ERR_clear_error();
1343+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => threw exception",
1344+ key_java_bytes);
1345+ return 0;
1346+ }
1347+
1348+ JNI_TRACE("bytes=%p EVP_PKEY_from_subject_public_key_info => %p", key_java_bytes, pkey.get());
1349+ return reinterpret_cast<uintptr_t>(pkey.release());
1350+ }
1351+
1352+ static jlong NativeCrypto_EVP_PKEY_from_raw_public_key(JNIEnv* env, jclass, jint pkey_type,
1353+ jbyteArray key_java_bytes) {
1354+ CHECK_ERROR_QUEUE_ON_RETURN;
1355+ JNI_TRACE("EVP_PKEY_from_raw_public_key(%p)", key_java_bytes);
1356+
1357+ if (key_java_bytes == nullptr) {
1358+ conscrypt::jniutil::throwNullPointerException(env, "key_java_bytes == null");
1359+ return 0;
1360+ }
1361+
1362+ ScopedByteArrayRO bytes(env, key_java_bytes);
1363+ if (bytes.get() == nullptr) {
1364+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
1365+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for key_java_bytes");
1366+ return 0;
1367+ }
1368+
1369+ const EVP_PKEY_ALG* alg = GetAlg(pkey_type);
1370+ if (alg == nullptr) {
1371+ conscrypt::jniutil::throwException(env, "java/lang/IllegalArgumentException",
1372+ "unsupported pkeyType");
1373+ return 0;
1374+ }
1375+
1376+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_from_raw_public_key(
1377+ alg, reinterpret_cast<const uint8_t*>(bytes.get()), bytes.size()));
1378+ if (!pkey) {
1379+ conscrypt::jniutil::throwParsingException(env, "Error parsing public key");
1380+ ERR_clear_error();
1381+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => threw exception", key_java_bytes);
1382+ return 0;
1383+ }
1384+
1385+ JNI_TRACE("bytes=%p EVP_PKEY_from_raw_public_key => %p", key_java_bytes, pkey.get());
1386+ return reinterpret_cast<uintptr_t>(pkey.release());
1387+ }
1388+
1389+ static jbyteArray NativeCrypto_EVP_PKEY_get_raw_public_key(JNIEnv* env, jclass, jobject pkey_ref) {
1390+ CHECK_ERROR_QUEUE_ON_RETURN;
1391+ JNI_TRACE("EVP_PKEY_get_raw_public_key(%p)", pkey_ref);
1392+
1393+ EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkey_ref);
1394+ if (pkey == nullptr) {
1395+ return nullptr;
1396+ }
1397+
1398+ size_t key_length = 0;
1399+ if (EVP_PKEY_get_raw_public_key(pkey, nullptr, &key_length) == 0) {
1400+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
1401+ return nullptr;
1402+ }
1403+
1404+ ScopedLocalRef<jbyteArray> raw_key_array(env,
1405+ env->NewByteArray(static_cast<jsize>(key_length)));
1406+ if (raw_key_array.get() == nullptr) {
1407+ JNI_TRACE("EVP_PKEY_get_raw_public_key: creating byte array failed");
1408+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key_array");
1409+ return nullptr;
1410+ }
1411+ ScopedByteArrayRW raw_key(env, raw_key_array.get());
1412+ if (raw_key.get() == nullptr) {
1413+ JNI_TRACE("EVP_PKEY_get_raw_public_key: using byte array failed");
1414+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for raw_key");
1415+ return nullptr;
1416+ }
1417+
1418+ if (EVP_PKEY_get_raw_public_key(pkey, reinterpret_cast<uint8_t*>(raw_key.get()), &key_length) ==
1419+ 0) {
1420+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_raw_public_key");
1421+ return nullptr;
1422+ }
1423+ return raw_key_array.release();
1424+ }
1425+
1426+ static jlong NativeCrypto_EVP_PKEY_from_private_seed(JNIEnv* env, jclass, jint pkeyType,
1427+ jbyteArray javaSeedBytes) {
1428+ CHECK_ERROR_QUEUE_ON_RETURN;
1429+ JNI_TRACE("EVP_PKEY_from_private_seed(%p)", javaSeedBytes);
1430+
1431+ if (javaSeedBytes == nullptr) {
1432+ JNI_TRACE("EVP_PKEY_from_private_seed => threw exception");
1433+ conscrypt::jniutil::throwNullPointerException(env, "javaSeedBytes == null");
1434+ return 0;
1435+ }
1436+
1437+ ScopedByteArrayRO seed(env, javaSeedBytes);
1438+ if (seed.get() == nullptr) {
1439+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
1440+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
1441+ return 0;
1442+ }
1443+
1444+ const EVP_PKEY_ALG* alg;
1445+ if (pkeyType == EVP_PKEY_ML_DSA_65) {
1446+ alg = EVP_pkey_ml_dsa_65();
1447+ } else if (pkeyType == EVP_PKEY_ML_DSA_87) {
1448+ alg = EVP_pkey_ml_dsa_87();
1449+ } else {
1450+ conscrypt::jniutil::throwInvalidKeyException(env, "unsupported pkeyType");
1451+ return 0;
1452+ }
1453+
1454+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_from_private_seed(
1455+ alg, reinterpret_cast<const uint8_t*>(seed.get()), seed.size()));
1456+
1457+ if (!pkey) {
1458+ conscrypt::jniutil::throwParsingException(env, "Error parsing private key");
1459+ ERR_clear_error();
1460+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => threw exception", javaSeedBytes);
1461+ return 0;
1462+ }
1463+
1464+ JNI_TRACE("bytes=%p EVP_PKEY_from_private_seed => %p", javaSeedBytes, pkey.get());
1465+ return reinterpret_cast<uintptr_t>(pkey.release());
1466+ }
1467+
1468+ static jbyteArray NativeCrypto_EVP_PKEY_get_private_seed(JNIEnv* env, jclass cls, jobject pkeyRef) {
1469+ CHECK_ERROR_QUEUE_ON_RETURN;
1470+ JNI_TRACE("EVP_PKEY_get_private_seed(%p)", pkeyRef);
1471+
1472+ EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
1473+ if (pkey == nullptr) {
1474+ return nullptr;
1475+ }
1476+
1477+ size_t seed_length = 0;
1478+ if (EVP_PKEY_get_private_seed(pkey, nullptr, &seed_length) == 0) {
1479+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
1480+ return nullptr;
1481+ }
1482+
1483+ ScopedLocalRef<jbyteArray> seedArray(env, env->NewByteArray(static_cast<jsize>(seed_length)));
1484+ if (seedArray.get() == nullptr) {
1485+ JNI_TRACE("EVP_PKEY_get_raw_private_key: creating byte array failed");
1486+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seedArray");
1487+ return nullptr;
1488+ }
1489+ ScopedByteArrayRW seed(env, seedArray.get());
1490+ if (seed.get() == nullptr) {
1491+ JNI_TRACE("EVP_PKEY_get_raw_private_key: using byte array failed");
1492+ conscrypt::jniutil::throwOutOfMemory(env, "Unable to allocate buffer for seed");
1493+ return nullptr;
1494+ }
1495+
1496+ if (EVP_PKEY_get_private_seed(pkey, reinterpret_cast<uint8_t*>(seed.get()), &seed_length) ==
1497+ 0) {
1498+ conscrypt::jniutil::throwExceptionFromBoringSSLError(env, "EVP_PKEY_get_private_seed");
1499+ return nullptr;
1500+ }
1501+ return seedArray.release();
1502+ }
12361503
12371504static jbyteArray NativeCrypto_EVP_raw_X25519_private_key(
12381505 JNIEnv* env, jclass cls, jbyteArray keyJavaBytes) {
@@ -3285,9 +3552,11 @@ static jlong evpDigestSignVerifyInit(JNIEnv* env,
32853552 }
32863553 JNI_TRACE("%s(%p, %p, %p) <- ptr", jniName, mdCtx, md, pkey);
32873554
3288- // For ED25519, md must be null, see
3555+ // Allow md to be null for ED25519, ML_DSA_65, and ML_DSA_87. See
32893556 // https://github.com/google/boringssl/blob/main/include/openssl/evp.h
3290- if (md == nullptr && (EVP_PKEY_id (pkey) != EVP_PKEY_ED25519)) {
3557+ int pkey_id = EVP_PKEY_id(pkey);
3558+ if (md == nullptr && (pkey_id != EVP_PKEY_ED25519 && pkey_id != EVP_PKEY_ML_DSA_65 &&
3559+ pkey_id != EVP_PKEY_ML_DSA_87)) {
32913560 JNI_TRACE("ctx=%p %s => md == null", mdCtx, jniName);
32923561 conscrypt::jniutil::throwNullPointerException(env, "md == null");
32933562 return 0;
@@ -3985,7 +4254,7 @@ static void NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jobject ctxRef,
39854254 encrypting ? 1 : 0);
39864255
39874256 if (ctx == nullptr) {
3988- JNI_TRACE (" EVP_CipherUpdate => ctx == null" );
4257+ JNI_TRACE("EVP_CipherInit_ex => ctx == null");
39894258 return;
39904259 }
39914260
@@ -12070,6 +12339,12 @@ static JNINativeMethod sNativeCryptoMethods[] = {
1207012339 CONSCRYPT_NATIVE_METHOD(EVP_PKEY_cmp, "(" REF_EVP_PKEY REF_EVP_PKEY ")I"),
1207112340 CONSCRYPT_NATIVE_METHOD(EVP_marshal_private_key, "(" REF_EVP_PKEY ")[B"),
1207212341 CONSCRYPT_NATIVE_METHOD(EVP_parse_private_key, "([B)J"),
12342+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_from_private_key_info, "([B[I)J"),
12343+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_from_subject_public_key_info, "([B[I)J"),
12344+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_from_raw_public_key, "(I[B)J"),
12345+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_get_raw_public_key, "(" REF_EVP_PKEY ")[B"),
12346+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_from_private_seed, "(I[B)J"),
12347+ CONSCRYPT_NATIVE_METHOD(EVP_PKEY_get_private_seed, "(" REF_EVP_PKEY ")[B"),
1207312348 CONSCRYPT_NATIVE_METHOD(EVP_raw_X25519_private_key, "([B)[B"),
1207412349 CONSCRYPT_NATIVE_METHOD(EVP_marshal_public_key, "(" REF_EVP_PKEY ")[B"),
1207512350 CONSCRYPT_NATIVE_METHOD(EVP_parse_public_key, "([B)J"),
0 commit comments