@@ -1162,3 +1162,228 @@ def test_rsa_prepare_key_raises_invalid_key_error_on_invalid_pem(self):
11621162
11631163 # Check that the exception message is correct
11641164 assert "Could not parse the provided public key." in str (excinfo .value )
1165+
1166+
1167+ @crypto_required
1168+ class TestECCurveValidation :
1169+ """Tests for ECDSA curve validation per RFC 7518 Section 3.4."""
1170+
1171+ def test_ec_curve_validation_rejects_wrong_curve_for_es256 (self ):
1172+ """ES256 should reject keys that are not P-256."""
1173+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256R1
1174+
1175+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256R1 )
1176+
1177+ # P-384 key should be rejected
1178+ with open (key_path ("jwk_ec_key_P-384.json" )) as keyfile :
1179+ p384_key = ECAlgorithm .from_jwk (keyfile .read ())
1180+
1181+ with pytest .raises (InvalidKeyError ) as excinfo :
1182+ algo .prepare_key (p384_key )
1183+ assert "secp384r1" in str (excinfo .value )
1184+ assert "secp256r1" in str (excinfo .value )
1185+
1186+ def test_ec_curve_validation_rejects_wrong_curve_for_es384 (self ):
1187+ """ES384 should reject keys that are not P-384."""
1188+ from cryptography .hazmat .primitives .asymmetric .ec import SECP384R1
1189+
1190+ algo = ECAlgorithm (ECAlgorithm .SHA384 , SECP384R1 )
1191+
1192+ # P-256 key should be rejected
1193+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1194+ p256_key = ECAlgorithm .from_jwk (keyfile .read ())
1195+
1196+ with pytest .raises (InvalidKeyError ) as excinfo :
1197+ algo .prepare_key (p256_key )
1198+ assert "secp256r1" in str (excinfo .value )
1199+ assert "secp384r1" in str (excinfo .value )
1200+
1201+ def test_ec_curve_validation_rejects_wrong_curve_for_es512 (self ):
1202+ """ES512 should reject keys that are not P-521."""
1203+ from cryptography .hazmat .primitives .asymmetric .ec import SECP521R1
1204+
1205+ algo = ECAlgorithm (ECAlgorithm .SHA512 , SECP521R1 )
1206+
1207+ # P-256 key should be rejected
1208+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1209+ p256_key = ECAlgorithm .from_jwk (keyfile .read ())
1210+
1211+ with pytest .raises (InvalidKeyError ) as excinfo :
1212+ algo .prepare_key (p256_key )
1213+ assert "secp256r1" in str (excinfo .value )
1214+ assert "secp521r1" in str (excinfo .value )
1215+
1216+ def test_ec_curve_validation_rejects_wrong_curve_for_es256k (self ):
1217+ """ES256K should reject keys that are not secp256k1."""
1218+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256K1
1219+
1220+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256K1 )
1221+
1222+ # P-256 key should be rejected
1223+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1224+ p256_key = ECAlgorithm .from_jwk (keyfile .read ())
1225+
1226+ with pytest .raises (InvalidKeyError ) as excinfo :
1227+ algo .prepare_key (p256_key )
1228+ assert "secp256r1" in str (excinfo .value )
1229+ assert "secp256k1" in str (excinfo .value )
1230+
1231+ def test_ec_curve_validation_accepts_correct_curve_for_es256 (self ):
1232+ """ES256 should accept P-256 keys."""
1233+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256R1
1234+
1235+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256R1 )
1236+
1237+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1238+ key = algo .from_jwk (keyfile .read ())
1239+ prepared = algo .prepare_key (key )
1240+ assert prepared is key
1241+
1242+ def test_ec_curve_validation_accepts_correct_curve_for_es384 (self ):
1243+ """ES384 should accept P-384 keys."""
1244+ from cryptography .hazmat .primitives .asymmetric .ec import SECP384R1
1245+
1246+ algo = ECAlgorithm (ECAlgorithm .SHA384 , SECP384R1 )
1247+
1248+ with open (key_path ("jwk_ec_key_P-384.json" )) as keyfile :
1249+ key = algo .from_jwk (keyfile .read ())
1250+ prepared = algo .prepare_key (key )
1251+ assert prepared is key
1252+
1253+ def test_ec_curve_validation_accepts_correct_curve_for_es512 (self ):
1254+ """ES512 should accept P-521 keys."""
1255+ from cryptography .hazmat .primitives .asymmetric .ec import SECP521R1
1256+
1257+ algo = ECAlgorithm (ECAlgorithm .SHA512 , SECP521R1 )
1258+
1259+ with open (key_path ("jwk_ec_key_P-521.json" )) as keyfile :
1260+ key = algo .from_jwk (keyfile .read ())
1261+ prepared = algo .prepare_key (key )
1262+ assert prepared is key
1263+
1264+ def test_ec_curve_validation_accepts_correct_curve_for_es256k (self ):
1265+ """ES256K should accept secp256k1 keys."""
1266+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256K1
1267+
1268+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256K1 )
1269+
1270+ with open (key_path ("jwk_ec_key_secp256k1.json" )) as keyfile :
1271+ key = algo .from_jwk (keyfile .read ())
1272+ prepared = algo .prepare_key (key )
1273+ assert prepared is key
1274+
1275+ def test_ec_curve_validation_rejects_p192_for_es256 (self ):
1276+ """ES256 should reject P-192 keys (weaker than P-256)."""
1277+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256R1
1278+
1279+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256R1 )
1280+
1281+ with open (key_path ("testkey_ec_secp192r1.priv" )) as keyfile :
1282+ with pytest .raises (InvalidKeyError ) as excinfo :
1283+ algo .prepare_key (keyfile .read ())
1284+ assert "secp192r1" in str (excinfo .value )
1285+ assert "secp256r1" in str (excinfo .value )
1286+
1287+ def test_ec_algorithm_without_expected_curve_accepts_any_curve (self ):
1288+ """ECAlgorithm without expected_curve should accept any curve (backwards compat)."""
1289+ algo = ECAlgorithm (ECAlgorithm .SHA256 )
1290+
1291+ # Should accept P-256
1292+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1293+ p256_key = algo .from_jwk (keyfile .read ())
1294+ algo .prepare_key (p256_key )
1295+
1296+ # Should accept P-384
1297+ with open (key_path ("jwk_ec_key_P-384.json" )) as keyfile :
1298+ p384_key = algo .from_jwk (keyfile .read ())
1299+ algo .prepare_key (p384_key )
1300+
1301+ # Should accept P-521
1302+ with open (key_path ("jwk_ec_key_P-521.json" )) as keyfile :
1303+ p521_key = algo .from_jwk (keyfile .read ())
1304+ algo .prepare_key (p521_key )
1305+
1306+ # Should accept secp256k1
1307+ with open (key_path ("jwk_ec_key_secp256k1.json" )) as keyfile :
1308+ secp256k1_key = algo .from_jwk (keyfile .read ())
1309+ algo .prepare_key (secp256k1_key )
1310+
1311+ def test_default_algorithms_have_correct_expected_curve (self ):
1312+ """Default algorithms returned by get_default_algorithms should have expected_curve set."""
1313+ from cryptography .hazmat .primitives .asymmetric .ec import (
1314+ SECP256K1 ,
1315+ SECP256R1 ,
1316+ SECP384R1 ,
1317+ SECP521R1 ,
1318+ )
1319+
1320+ from jwt .algorithms import get_default_algorithms
1321+
1322+ algorithms = get_default_algorithms ()
1323+
1324+ es256 = algorithms ["ES256" ]
1325+ assert isinstance (es256 , ECAlgorithm )
1326+ assert es256 .expected_curve == SECP256R1
1327+
1328+ es256k = algorithms ["ES256K" ]
1329+ assert isinstance (es256k , ECAlgorithm )
1330+ assert es256k .expected_curve == SECP256K1
1331+
1332+ es384 = algorithms ["ES384" ]
1333+ assert isinstance (es384 , ECAlgorithm )
1334+ assert es384 .expected_curve == SECP384R1
1335+
1336+ es521 = algorithms ["ES521" ]
1337+ assert isinstance (es521 , ECAlgorithm )
1338+ assert es521 .expected_curve == SECP521R1
1339+
1340+ es512 = algorithms ["ES512" ]
1341+ assert isinstance (es512 , ECAlgorithm )
1342+ assert es512 .expected_curve == SECP521R1
1343+
1344+ def test_ec_curve_validation_with_pem_key (self ):
1345+ """Curve validation should work with PEM-formatted keys."""
1346+ from cryptography .hazmat .primitives .asymmetric .ec import SECP256R1
1347+
1348+ algo = ECAlgorithm (ECAlgorithm .SHA256 , SECP256R1 )
1349+
1350+ # P-256 PEM key should be accepted
1351+ with open (key_path ("testkey_ec.priv" )) as keyfile :
1352+ algo .prepare_key (keyfile .read ())
1353+
1354+ # P-192 PEM key should be rejected
1355+ with open (key_path ("testkey_ec_secp192r1.priv" )) as keyfile :
1356+ with pytest .raises (InvalidKeyError ):
1357+ algo .prepare_key (keyfile .read ())
1358+
1359+ def test_jwt_encode_decode_rejects_wrong_curve (self ):
1360+ """Integration test: jwt.encode/decode should reject wrong curve keys."""
1361+ import jwt
1362+
1363+ # Use P-384 key with ES256 algorithm (expects P-256)
1364+ with open (key_path ("jwk_ec_key_P-384.json" )) as keyfile :
1365+ p384_key = ECAlgorithm .from_jwk (keyfile .read ())
1366+
1367+ # Encoding should fail
1368+ with pytest .raises (InvalidKeyError ):
1369+ jwt .encode ({"hello" : "world" }, p384_key , algorithm = "ES256" )
1370+
1371+ # Create a valid token with P-256 key
1372+ with open (key_path ("jwk_ec_key_P-256.json" )) as keyfile :
1373+ p256_key = ECAlgorithm .from_jwk (keyfile .read ())
1374+
1375+ token = jwt .encode ({"hello" : "world" }, p256_key , algorithm = "ES256" )
1376+
1377+ # Decoding with wrong curve key should fail
1378+ with open (key_path ("jwk_ec_pub_P-384.json" )) as keyfile :
1379+ p384_pub_key = ECAlgorithm .from_jwk (keyfile .read ())
1380+
1381+ with pytest .raises (InvalidKeyError ):
1382+ jwt .decode (token , p384_pub_key , algorithms = ["ES256" ])
1383+
1384+ # Decoding with correct curve key should succeed
1385+ with open (key_path ("jwk_ec_pub_P-256.json" )) as keyfile :
1386+ p256_pub_key = ECAlgorithm .from_jwk (keyfile .read ())
1387+
1388+ decoded = jwt .decode (token , p256_pub_key , algorithms = ["ES256" ])
1389+ assert decoded == {"hello" : "world" }
0 commit comments