Skip to content

Commit a909a74

Browse files
bors[bot]zugzwang
andcommitted
Merge #194
194: Fix checks on curve parameters r=jethrogb a=zugzwang On instantiating a curve by parameters, the code checks that all field elements are non-zero in 𝔽ₚ. This is not necessary, and forbids useful curves such as e.g. the Barreto-Naehrig pairing-friendly curves, of the form y² = x³ + 257 (e.g. `a = 0`), and secp256k1 (used in Bitcoin, but can be instantiated by name). Co-authored-by: Francisco Vial-Prado <[email protected]>
1 parent 17e5f99 commit a909a74

File tree

1 file changed

+164
-4
lines changed

1 file changed

+164
-4
lines changed

mbedtls/src/ecp/mod.rs

+164-4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ impl EcGroup {
7979
Ok(ret)
8080
}
8181

82+
/// Initialize an EcGroup with custom group parameters.
83+
///
84+
/// HAZMAT: This function DOES NOT perform a full check on parameters
85+
/// against all known attacks. The caller MUST make sure that parameters are
86+
/// trusted. Failing to comply with this requirement may result in the use
87+
/// of INSECURE curves. Prefer [EcGroup::new] with known curves listed in
88+
/// [EcGroupId].
8289
pub fn from_parameters(
8390
p: Mpi,
8491
a: Mpi,
@@ -96,15 +103,16 @@ impl EcGroup {
96103
let zero = Mpi::new(0)?;
97104

98105
// basic bounds checking
99-
if &a <= &zero
106+
if &a < &zero
100107
|| &a >= &p
101-
|| &b <= &zero
108+
|| &b < &zero
102109
|| &b >= &p
103-
|| &g_x <= &zero
110+
|| &g_x < &zero
104111
|| &g_x >= &p
105-
|| &g_y <= &zero
112+
|| &g_y < &zero
106113
|| &g_y >= &p
107114
|| &order <= &zero
115+
|| (&a == &zero && &b == &zero)
108116
{
109117
return Err(Error::EcpBadInputData);
110118
}
@@ -191,6 +199,8 @@ impl EcGroup {
191199
match self.group_id()? {
192200
EcGroupId::Curve25519 => Ok(8),
193201
EcGroupId::Curve448 => Ok(4),
202+
// Requires a point-counting algorithm such as SEA.
203+
EcGroupId::None => Err(Error::EcpFeatureUnavailable),
194204
_ => Ok(1),
195205
}
196206
}
@@ -754,4 +764,154 @@ mod tests {
754764
let pt3 = pt1.clone();
755765
assert_eq!(pt2.eq(&pt3).unwrap(), true);
756766
}
767+
768+
#[cfg(feature = "std")]
769+
struct Params<'a> {
770+
p: &'a str,
771+
a: &'a str,
772+
b: &'a str,
773+
g_x: &'a str,
774+
g_y: &'a str,
775+
n: &'a str,
776+
}
777+
778+
#[cfg(feature = "std")]
779+
impl Into<super::Result<EcGroup>> for Params<'_> {
780+
fn into(self) -> super::Result<EcGroup> {
781+
use std::str::FromStr;
782+
EcGroup::from_parameters(
783+
Mpi::from_str(self.p)?,
784+
Mpi::from_str(self.a)?,
785+
Mpi::from_str(self.b)?,
786+
Mpi::from_str(self.g_x)?,
787+
Mpi::from_str(self.g_y)?,
788+
Mpi::from_str(self.n)?,
789+
)
790+
}
791+
}
792+
793+
#[test]
794+
#[cfg(feature = "std")]
795+
fn pathological_parameters() {
796+
// y² = x³ mod 7 (note a == b == 0)
797+
let singular: super::Result<_> = Params {
798+
p: "0x07",
799+
a: "0x00",
800+
b: "0x00",
801+
g_x: "0x01",
802+
g_y: "0x02",
803+
n: "0x0b",
804+
}.into();
805+
assert!(singular.is_err());
806+
}
807+
808+
#[test]
809+
#[cfg(feature = "std")]
810+
fn bad_generators() {
811+
// y² = x³ + x + 6 (mod 7) with bad generator (1, 2) and prime order 11
812+
let small_curve: super::Result<_> = Params {
813+
p: "0x07",
814+
a: "0x01",
815+
b: "0x06",
816+
g_x: "0x01",
817+
g_y: "0x02",
818+
n: "0x0b",
819+
}.into();
820+
assert!(small_curve.is_err());
821+
822+
// y² = x³ + x + 6 (mod 7) with bad generator (0, 0) and prime order 11
823+
let small_curve_zero_gen: super::Result<_> = Params {
824+
p: "0x07",
825+
a: "0x01",
826+
b: "0x06",
827+
g_x: "0x00",
828+
g_y: "0x00",
829+
n: "0x0b",
830+
}.into();
831+
assert!(small_curve_zero_gen.is_err());
832+
}
833+
834+
#[test]
835+
#[cfg(feature = "std")]
836+
fn unknown_cofactor() {
837+
// y² = x³ + x + 6 (mod 7) with generator (1, 6) and prime order 11
838+
let small_curve: super::Result<_> = Params {
839+
p: "0x07",
840+
a: "0x01",
841+
b: "0x06",
842+
g_x: "0x01",
843+
g_y: "0x06",
844+
n: "0x0b",
845+
}.into();
846+
assert!(small_curve.unwrap().cofactor().is_err());
847+
}
848+
849+
#[test]
850+
#[cfg(feature = "std")]
851+
fn zero_params_curves() {
852+
use super::Result;
853+
// Barreto-Naehrig 254, note a = 0
854+
let bn254: Result<_> = Params {
855+
p: "0x2523648240000001BA344D80000000086121000000000013A700000000000013",
856+
a: "0x0000000000000000000000000000000000000000000000000000000000000000",
857+
b: "0x0000000000000000000000000000000000000000000000000000000000000002",
858+
g_x: "0x2523648240000001BA344D80000000086121000000000013A700000000000012",
859+
g_y: "0x0000000000000000000000000000000000000000000000000000000000000001",
860+
n: "0x2523648240000001BA344D8000000007FF9F800000000010A10000000000000D",
861+
}.into();
862+
assert!(bn254.is_ok());
863+
864+
// Prescribed embedded degree of 12, BLS12-381
865+
let bls12_381: Result<_> = Params {
866+
p: "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
867+
a: "0x00",
868+
b: "0x04",
869+
g_x: "0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB",
870+
g_y: "0x08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1",
871+
n: "0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001",
872+
}.into();
873+
assert!(bls12_381.is_ok());
874+
875+
// Fp256BN
876+
let fp256_bn: Result<_> = Params {
877+
p: "0xfffffffffffcf0cd46e5f25eee71a49f0cdc65fb12980a82d3292ddbaed33013",
878+
a: "0x00",
879+
b: "0x03",
880+
g_x: "0x01",
881+
g_y: "0x02",
882+
n: "0xfffffffffffcf0cd46e5f25eee71a49e0cdc65fb1299921af62d536cd10b500d",
883+
}.into();
884+
assert!(fp256_bn.is_ok());
885+
886+
// id-GostR3410-2001-CryptoPro-C-ParamSet, note g_x = 0
887+
let gost_r3410: Result<_> = Params {
888+
p: "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b",
889+
a: "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598",
890+
b: "0x805a",
891+
g_x: "0x00",
892+
g_y: "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67",
893+
n: "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9",
894+
}.into();
895+
assert!(gost_r3410.is_ok());
896+
897+
// secp256k1 (Bitcoin), note a = 0
898+
let my_secp256k1: Result<EcGroup> = Params {
899+
p: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
900+
a: "0x0000000000000000000000000000000000000000000000000000000000000000",
901+
b: "0x0000000000000000000000000000000000000000000000000000000000000007",
902+
g_x: "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
903+
g_y: "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
904+
n: "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
905+
}.into();
906+
assert!(my_secp256k1.is_ok());
907+
let my_secp256k1 = my_secp256k1.unwrap();
908+
909+
// We compare against the known SecP256K1
910+
let secp256k1 = EcGroup::new(EcGroupId::SecP256K1).unwrap();
911+
assert!(my_secp256k1.p() == secp256k1.p());
912+
assert!(my_secp256k1.a() == secp256k1.a());
913+
assert!(my_secp256k1.b() == secp256k1.b());
914+
assert!(my_secp256k1.generator() == secp256k1.generator());
915+
assert!(my_secp256k1.order() == secp256k1.order());
916+
}
757917
}

0 commit comments

Comments
 (0)