1 //! Elliptic Curve 2 //! 3 //! Cryptography relies on the difficulty of solving mathematical problems, such as the factor 4 //! of large integers composed of two large prime numbers and the discrete logarithm of a 5 //! random elliptic curve. This module provides low-level features of the latter. 6 //! Elliptic Curve protocols can provide the same security with smaller keys. 7 //! 8 //! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible 9 //! trinomial or pentanomial. Being a generic interface to a wide range of algorithms, 10 //! the curves are generally referenced by [`EcGroup`]. There are many built-in groups 11 //! found in [`Nid`]. 12 //! 13 //! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography]. 14 //! 15 //! [`EcGroup`]: struct.EcGroup.html 16 //! [`Nid`]: ../nid/struct.Nid.html 17 //! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography 18 use cfg_if::cfg_if; 19 use foreign_types::{ForeignType, ForeignTypeRef}; 20 use libc::c_int; 21 use std::fmt; 22 use std::ptr; 23 24 use crate::bn::{BigNum, BigNumContextRef, BigNumRef}; 25 use crate::error::ErrorStack; 26 use crate::nid::Nid; 27 use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; 28 use crate::util::ForeignTypeRefExt; 29 use crate::{cvt, cvt_n, cvt_p, init}; 30 use openssl_macros::corresponds; 31 32 cfg_if! { 33 if #[cfg(not(boringssl))] { 34 use std::ffi::CString; 35 use crate::string::OpensslString; 36 } 37 } 38 39 /// Compressed or Uncompressed conversion 40 /// 41 /// Conversion from the binary value of the point on the curve is performed in one of 42 /// compressed, uncompressed, or hybrid conversions. The default is compressed, except 43 /// for binary curves. 44 /// 45 /// Further documentation is available in the [X9.62] standard. 46 /// 47 /// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf 48 #[derive(Copy, Clone)] 49 pub struct PointConversionForm(ffi::point_conversion_form_t); 50 51 impl PointConversionForm { 52 /// Compressed conversion from point value. 53 pub const COMPRESSED: PointConversionForm = 54 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); 55 56 /// Uncompressed conversion from point value. 57 pub const UNCOMPRESSED: PointConversionForm = 58 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); 59 60 /// Performs both compressed and uncompressed conversions. 61 pub const HYBRID: PointConversionForm = 62 PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); 63 } 64 65 /// Named Curve or Explicit 66 /// 67 /// This type acts as a boolean as to whether the `EcGroup` is named or explicit. 68 #[derive(Copy, Clone, Debug, PartialEq)] 69 pub struct Asn1Flag(c_int); 70 71 impl Asn1Flag { 72 /// Curve defined using polynomial parameters 73 /// 74 /// Most applications use a named EC_GROUP curve, however, support 75 /// is included to explicitly define the curve used to calculate keys 76 /// This information would need to be known by both endpoint to make communication 77 /// effective. 78 /// 79 /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. 80 /// Man page documents that 0 can be used in older versions. 81 /// 82 /// OpenSSL documentation at [`EC_GROUP`] 83 /// 84 /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/crypto/EC_GROUP_get_seed_len.html 85 pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); 86 87 /// Standard Curves 88 /// 89 /// Curves that make up the typical encryption use cases. The collection of curves 90 /// are well known but extensible. 91 /// 92 /// OpenSSL documentation at [`EC_GROUP`] 93 /// 94 /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html 95 pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); 96 } 97 98 foreign_type_and_impl_send_sync! { 99 type CType = ffi::EC_GROUP; 100 fn drop = ffi::EC_GROUP_free; 101 102 /// Describes the curve 103 /// 104 /// A curve can be of the named curve type. These curves can be discovered 105 /// using openssl binary `openssl ecparam -list_curves`. Other operations 106 /// are available in the [wiki]. These named curves are available in the 107 /// [`Nid`] module. 108 /// 109 /// Curves can also be generated using prime field parameters or a binary field. 110 /// 111 /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary 112 /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have 113 /// assured security. To prevent accidental vulnerabilities, they should 114 /// be preferred. 115 /// 116 /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations 117 /// [`Nid`]: ../nid/index.html 118 pub struct EcGroup; 119 /// Reference to [`EcGroup`] 120 /// 121 /// [`EcGroup`]: struct.EcGroup.html 122 pub struct EcGroupRef; 123 } 124 125 impl EcGroup { 126 /// Returns the group of a standard named curve. 127 /// 128 /// # Examples 129 /// 130 /// ``` 131 /// # fn main() -> Result<(), Box<dyn std::error::Error>> { 132 /// use openssl::nid::Nid; 133 /// use openssl::ec::{EcGroup, EcKey}; 134 /// 135 /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve 136 /// let group = EcGroup::from_curve_name(nid)?; 137 /// let key = EcKey::generate(&group)?; 138 /// # Ok(()) } 139 /// ``` 140 #[corresponds(EC_GROUP_new_by_curve_name)] from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack>141 pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> { 142 unsafe { 143 init(); 144 cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) 145 } 146 } 147 148 /// Returns the group for given parameters 149 #[corresponds(EC_GROUP_new_curve_GFp)] from_components( p: BigNum, a: BigNum, b: BigNum, ctx: &mut BigNumContextRef, ) -> Result<EcGroup, ErrorStack>150 pub fn from_components( 151 p: BigNum, 152 a: BigNum, 153 b: BigNum, 154 ctx: &mut BigNumContextRef, 155 ) -> Result<EcGroup, ErrorStack> { 156 unsafe { 157 cvt_p(ffi::EC_GROUP_new_curve_GFp( 158 p.as_ptr(), 159 a.as_ptr(), 160 b.as_ptr(), 161 ctx.as_ptr(), 162 )) 163 .map(EcGroup) 164 } 165 } 166 } 167 168 impl EcGroupRef { 169 /// Places the components of a curve over a prime field in the provided `BigNum`s. 170 /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. 171 #[corresponds(EC_GROUP_get_curve_GFp)] components_gfp( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>172 pub fn components_gfp( 173 &self, 174 p: &mut BigNumRef, 175 a: &mut BigNumRef, 176 b: &mut BigNumRef, 177 ctx: &mut BigNumContextRef, 178 ) -> Result<(), ErrorStack> { 179 unsafe { 180 cvt(ffi::EC_GROUP_get_curve_GFp( 181 self.as_ptr(), 182 p.as_ptr(), 183 a.as_ptr(), 184 b.as_ptr(), 185 ctx.as_ptr(), 186 )) 187 .map(|_| ()) 188 } 189 } 190 191 /// Places the components of a curve over a binary field in the provided `BigNum`s. 192 /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`. 193 /// 194 /// In this form `p` relates to the irreducible polynomial. Each bit represents 195 /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on 196 /// using a trinomial or pentanomial. 197 #[corresponds(EC_GROUP_get_curve_GF2m)] 198 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] 199 #[cfg(not(boringssl))] components_gf2m( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>200 pub fn components_gf2m( 201 &self, 202 p: &mut BigNumRef, 203 a: &mut BigNumRef, 204 b: &mut BigNumRef, 205 ctx: &mut BigNumContextRef, 206 ) -> Result<(), ErrorStack> { 207 unsafe { 208 cvt(ffi::EC_GROUP_get_curve_GF2m( 209 self.as_ptr(), 210 p.as_ptr(), 211 a.as_ptr(), 212 b.as_ptr(), 213 ctx.as_ptr(), 214 )) 215 .map(|_| ()) 216 } 217 } 218 219 /// Places the cofactor of the group in the provided `BigNum`. 220 #[corresponds(EC_GROUP_get_cofactor)] cofactor( &self, cofactor: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>221 pub fn cofactor( 222 &self, 223 cofactor: &mut BigNumRef, 224 ctx: &mut BigNumContextRef, 225 ) -> Result<(), ErrorStack> { 226 unsafe { 227 cvt(ffi::EC_GROUP_get_cofactor( 228 self.as_ptr(), 229 cofactor.as_ptr(), 230 ctx.as_ptr(), 231 )) 232 .map(|_| ()) 233 } 234 } 235 236 /// Returns the degree of the curve. 237 #[corresponds(EC_GROUP_get_degree)] degree(&self) -> u32238 pub fn degree(&self) -> u32 { 239 unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } 240 } 241 242 /// Returns the number of bits in the group order. 243 #[corresponds(EC_GROUP_order_bits)] 244 #[cfg(ossl110)] order_bits(&self) -> u32245 pub fn order_bits(&self) -> u32 { 246 unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } 247 } 248 249 /// Returns the generator for the given curve as an [`EcPoint`]. 250 #[corresponds(EC_GROUP_get0_generator)] generator(&self) -> &EcPointRef251 pub fn generator(&self) -> &EcPointRef { 252 unsafe { 253 let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); 254 EcPointRef::from_const_ptr(ptr) 255 } 256 } 257 258 /// Sets the generator point for the given curve 259 #[corresponds(EC_GROUP_set_generator)] set_generator( &mut self, generator: EcPoint, order: BigNum, cofactor: BigNum, ) -> Result<(), ErrorStack>260 pub fn set_generator( 261 &mut self, 262 generator: EcPoint, 263 order: BigNum, 264 cofactor: BigNum, 265 ) -> Result<(), ErrorStack> { 266 unsafe { 267 cvt(ffi::EC_GROUP_set_generator( 268 self.as_ptr(), 269 generator.as_ptr(), 270 order.as_ptr(), 271 cofactor.as_ptr(), 272 )) 273 .map(|_| ()) 274 } 275 } 276 277 /// Places the order of the curve in the provided `BigNum`. 278 #[corresponds(EC_GROUP_get_order)] order( &self, order: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>279 pub fn order( 280 &self, 281 order: &mut BigNumRef, 282 ctx: &mut BigNumContextRef, 283 ) -> Result<(), ErrorStack> { 284 unsafe { 285 cvt(ffi::EC_GROUP_get_order( 286 self.as_ptr(), 287 order.as_ptr(), 288 ctx.as_ptr(), 289 )) 290 .map(|_| ()) 291 } 292 } 293 294 /// Sets the flag determining if the group corresponds to a named curve or must be explicitly 295 /// parameterized. 296 /// 297 /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL 298 /// 1.1.0. 299 #[corresponds(EC_GROUP_set_asn1_flag)] set_asn1_flag(&mut self, flag: Asn1Flag)300 pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { 301 unsafe { 302 ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); 303 } 304 } 305 306 /// Gets the flag determining if the group corresponds to a named curve. 307 #[corresponds(EC_GROUP_get_asn1_flag)] asn1_flag(&self) -> Asn1Flag308 pub fn asn1_flag(&self) -> Asn1Flag { 309 unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } 310 } 311 312 /// Returns the name of the curve, if a name is associated. 313 #[corresponds(EC_GROUP_get_curve_name)] curve_name(&self) -> Option<Nid>314 pub fn curve_name(&self) -> Option<Nid> { 315 let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; 316 if nid > 0 { 317 Some(Nid::from_raw(nid)) 318 } else { 319 None 320 } 321 } 322 } 323 324 foreign_type_and_impl_send_sync! { 325 type CType = ffi::EC_POINT; 326 fn drop = ffi::EC_POINT_free; 327 328 /// Represents a point on the curve 329 pub struct EcPoint; 330 /// A reference a borrowed [`EcPoint`]. 331 pub struct EcPointRef; 332 } 333 334 impl EcPointRef { 335 /// Computes `a + b`, storing the result in `self`. 336 #[corresponds(EC_POINT_add)] add( &mut self, group: &EcGroupRef, a: &EcPointRef, b: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>337 pub fn add( 338 &mut self, 339 group: &EcGroupRef, 340 a: &EcPointRef, 341 b: &EcPointRef, 342 ctx: &mut BigNumContextRef, 343 ) -> Result<(), ErrorStack> { 344 unsafe { 345 cvt(ffi::EC_POINT_add( 346 group.as_ptr(), 347 self.as_ptr(), 348 a.as_ptr(), 349 b.as_ptr(), 350 ctx.as_ptr(), 351 )) 352 .map(|_| ()) 353 } 354 } 355 356 /// Computes `q * m`, storing the result in `self`. 357 #[corresponds(EC_POINT_mul)] mul( &mut self, group: &EcGroupRef, q: &EcPointRef, m: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack>358 pub fn mul( 359 &mut self, 360 group: &EcGroupRef, 361 q: &EcPointRef, 362 m: &BigNumRef, 363 // FIXME should be &mut 364 ctx: &BigNumContextRef, 365 ) -> Result<(), ErrorStack> { 366 unsafe { 367 cvt(ffi::EC_POINT_mul( 368 group.as_ptr(), 369 self.as_ptr(), 370 ptr::null(), 371 q.as_ptr(), 372 m.as_ptr(), 373 ctx.as_ptr(), 374 )) 375 .map(|_| ()) 376 } 377 } 378 379 /// Computes `generator * n`, storing the result in `self`. 380 #[corresponds(EC_POINT_mul)] mul_generator( &mut self, group: &EcGroupRef, n: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack>381 pub fn mul_generator( 382 &mut self, 383 group: &EcGroupRef, 384 n: &BigNumRef, 385 // FIXME should be &mut 386 ctx: &BigNumContextRef, 387 ) -> Result<(), ErrorStack> { 388 unsafe { 389 cvt(ffi::EC_POINT_mul( 390 group.as_ptr(), 391 self.as_ptr(), 392 n.as_ptr(), 393 ptr::null(), 394 ptr::null(), 395 ctx.as_ptr(), 396 )) 397 .map(|_| ()) 398 } 399 } 400 401 /// Computes `generator * n + q * m`, storing the result in `self`. 402 #[corresponds(EC_POINT_mul)] mul_full( &mut self, group: &EcGroupRef, n: &BigNumRef, q: &EcPointRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>403 pub fn mul_full( 404 &mut self, 405 group: &EcGroupRef, 406 n: &BigNumRef, 407 q: &EcPointRef, 408 m: &BigNumRef, 409 ctx: &mut BigNumContextRef, 410 ) -> Result<(), ErrorStack> { 411 unsafe { 412 cvt(ffi::EC_POINT_mul( 413 group.as_ptr(), 414 self.as_ptr(), 415 n.as_ptr(), 416 q.as_ptr(), 417 m.as_ptr(), 418 ctx.as_ptr(), 419 )) 420 .map(|_| ()) 421 } 422 } 423 424 /// Inverts `self`. 425 #[corresponds(EC_POINT_invert)] 426 // FIXME should be mutable invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack>427 pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { 428 unsafe { 429 cvt(ffi::EC_POINT_invert( 430 group.as_ptr(), 431 self.as_ptr(), 432 ctx.as_ptr(), 433 )) 434 .map(|_| ()) 435 } 436 } 437 438 /// Serializes the point to a binary representation. 439 #[corresponds(EC_POINT_point2oct)] to_bytes( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result<Vec<u8>, ErrorStack>440 pub fn to_bytes( 441 &self, 442 group: &EcGroupRef, 443 form: PointConversionForm, 444 ctx: &mut BigNumContextRef, 445 ) -> Result<Vec<u8>, ErrorStack> { 446 unsafe { 447 let len = ffi::EC_POINT_point2oct( 448 group.as_ptr(), 449 self.as_ptr(), 450 form.0, 451 ptr::null_mut(), 452 0, 453 ctx.as_ptr(), 454 ); 455 if len == 0 { 456 return Err(ErrorStack::get()); 457 } 458 let mut buf = vec![0; len]; 459 let len = ffi::EC_POINT_point2oct( 460 group.as_ptr(), 461 self.as_ptr(), 462 form.0, 463 buf.as_mut_ptr(), 464 len, 465 ctx.as_ptr(), 466 ); 467 if len == 0 { 468 Err(ErrorStack::get()) 469 } else { 470 Ok(buf) 471 } 472 } 473 } 474 475 /// Serializes the point to a hexadecimal string representation. 476 #[corresponds(EC_POINT_point2hex)] 477 #[cfg(not(boringssl))] to_hex_str( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result<OpensslString, ErrorStack>478 pub fn to_hex_str( 479 &self, 480 group: &EcGroupRef, 481 form: PointConversionForm, 482 ctx: &mut BigNumContextRef, 483 ) -> Result<OpensslString, ErrorStack> { 484 unsafe { 485 let buf = cvt_p(ffi::EC_POINT_point2hex( 486 group.as_ptr(), 487 self.as_ptr(), 488 form.0, 489 ctx.as_ptr(), 490 ))?; 491 Ok(OpensslString::from_ptr(buf)) 492 } 493 } 494 495 /// Creates a new point on the specified curve with the same value. 496 #[corresponds(EC_POINT_dup)] to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack>497 pub fn to_owned(&self, group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { 498 unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) } 499 } 500 501 /// Determines if this point is equal to another. 502 #[corresponds(EC_POINT_cmp)] eq( &self, group: &EcGroupRef, other: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result<bool, ErrorStack>503 pub fn eq( 504 &self, 505 group: &EcGroupRef, 506 other: &EcPointRef, 507 ctx: &mut BigNumContextRef, 508 ) -> Result<bool, ErrorStack> { 509 unsafe { 510 let res = cvt_n(ffi::EC_POINT_cmp( 511 group.as_ptr(), 512 self.as_ptr(), 513 other.as_ptr(), 514 ctx.as_ptr(), 515 ))?; 516 Ok(res == 0) 517 } 518 } 519 520 /// Places affine coordinates of a curve over a prime field in the provided 521 /// `x` and `y` `BigNum`s. 522 #[corresponds(EC_POINT_get_affine_coordinates)] 523 #[cfg(any(ossl111, boringssl, libressl350))] affine_coordinates( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>524 pub fn affine_coordinates( 525 &self, 526 group: &EcGroupRef, 527 x: &mut BigNumRef, 528 y: &mut BigNumRef, 529 ctx: &mut BigNumContextRef, 530 ) -> Result<(), ErrorStack> { 531 unsafe { 532 cvt(ffi::EC_POINT_get_affine_coordinates( 533 group.as_ptr(), 534 self.as_ptr(), 535 x.as_ptr(), 536 y.as_ptr(), 537 ctx.as_ptr(), 538 )) 539 .map(|_| ()) 540 } 541 } 542 543 /// Places affine coordinates of a curve over a prime field in the provided 544 /// `x` and `y` `BigNum`s 545 #[corresponds(EC_POINT_get_affine_coordinates_GFp)] affine_coordinates_gfp( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>546 pub fn affine_coordinates_gfp( 547 &self, 548 group: &EcGroupRef, 549 x: &mut BigNumRef, 550 y: &mut BigNumRef, 551 ctx: &mut BigNumContextRef, 552 ) -> Result<(), ErrorStack> { 553 unsafe { 554 cvt(ffi::EC_POINT_get_affine_coordinates_GFp( 555 group.as_ptr(), 556 self.as_ptr(), 557 x.as_ptr(), 558 y.as_ptr(), 559 ctx.as_ptr(), 560 )) 561 .map(|_| ()) 562 } 563 } 564 565 /// Sets affine coordinates of a curve over a prime field using the provided 566 /// `x` and `y` `BigNum`s 567 #[corresponds(EC_POINT_set_affine_coordinates_GFp)] set_affine_coordinates_gfp( &mut self, group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>568 pub fn set_affine_coordinates_gfp( 569 &mut self, 570 group: &EcGroupRef, 571 x: &BigNumRef, 572 y: &BigNumRef, 573 ctx: &mut BigNumContextRef, 574 ) -> Result<(), ErrorStack> { 575 unsafe { 576 cvt(ffi::EC_POINT_set_affine_coordinates_GFp( 577 group.as_ptr(), 578 self.as_ptr(), 579 x.as_ptr(), 580 y.as_ptr(), 581 ctx.as_ptr(), 582 )) 583 .map(|_| ()) 584 } 585 } 586 587 /// Places affine coordinates of a curve over a binary field in the provided 588 /// `x` and `y` `BigNum`s 589 #[corresponds(EC_POINT_get_affine_coordinates_GF2m)] 590 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] 591 #[cfg(not(boringssl))] affine_coordinates_gf2m( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack>592 pub fn affine_coordinates_gf2m( 593 &self, 594 group: &EcGroupRef, 595 x: &mut BigNumRef, 596 y: &mut BigNumRef, 597 ctx: &mut BigNumContextRef, 598 ) -> Result<(), ErrorStack> { 599 unsafe { 600 cvt(ffi::EC_POINT_get_affine_coordinates_GF2m( 601 group.as_ptr(), 602 self.as_ptr(), 603 x.as_ptr(), 604 y.as_ptr(), 605 ctx.as_ptr(), 606 )) 607 .map(|_| ()) 608 } 609 } 610 611 /// Checks if point is infinity 612 #[corresponds(EC_POINT_is_at_infinity)] is_infinity(&self, group: &EcGroupRef) -> bool613 pub fn is_infinity(&self, group: &EcGroupRef) -> bool { 614 unsafe { 615 let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); 616 res == 1 617 } 618 } 619 620 /// Checks if point is on a given curve 621 #[corresponds(EC_POINT_is_on_curve)] is_on_curve( &self, group: &EcGroupRef, ctx: &mut BigNumContextRef, ) -> Result<bool, ErrorStack>622 pub fn is_on_curve( 623 &self, 624 group: &EcGroupRef, 625 ctx: &mut BigNumContextRef, 626 ) -> Result<bool, ErrorStack> { 627 unsafe { 628 let res = cvt_n(ffi::EC_POINT_is_on_curve( 629 group.as_ptr(), 630 self.as_ptr(), 631 ctx.as_ptr(), 632 ))?; 633 Ok(res == 1) 634 } 635 } 636 } 637 638 impl EcPoint { 639 /// Creates a new point on the specified curve. 640 #[corresponds(EC_POINT_new)] new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack>641 pub fn new(group: &EcGroupRef) -> Result<EcPoint, ErrorStack> { 642 unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } 643 } 644 645 /// Creates point from a binary representation 646 #[corresponds(EC_POINT_oct2point)] from_bytes( group: &EcGroupRef, buf: &[u8], ctx: &mut BigNumContextRef, ) -> Result<EcPoint, ErrorStack>647 pub fn from_bytes( 648 group: &EcGroupRef, 649 buf: &[u8], 650 ctx: &mut BigNumContextRef, 651 ) -> Result<EcPoint, ErrorStack> { 652 let point = EcPoint::new(group)?; 653 unsafe { 654 cvt(ffi::EC_POINT_oct2point( 655 group.as_ptr(), 656 point.as_ptr(), 657 buf.as_ptr(), 658 buf.len(), 659 ctx.as_ptr(), 660 ))?; 661 } 662 Ok(point) 663 } 664 665 /// Creates point from a hexadecimal string representation 666 #[corresponds(EC_POINT_hex2point)] 667 #[cfg(not(boringssl))] from_hex_str( group: &EcGroupRef, s: &str, ctx: &mut BigNumContextRef, ) -> Result<EcPoint, ErrorStack>668 pub fn from_hex_str( 669 group: &EcGroupRef, 670 s: &str, 671 ctx: &mut BigNumContextRef, 672 ) -> Result<EcPoint, ErrorStack> { 673 let point = EcPoint::new(group)?; 674 unsafe { 675 let c_str = CString::new(s.as_bytes()).unwrap(); 676 cvt_p(ffi::EC_POINT_hex2point( 677 group.as_ptr(), 678 c_str.as_ptr() as *const _, 679 point.as_ptr(), 680 ctx.as_ptr(), 681 ))?; 682 } 683 Ok(point) 684 } 685 } 686 687 generic_foreign_type_and_impl_send_sync! { 688 type CType = ffi::EC_KEY; 689 fn drop = ffi::EC_KEY_free; 690 691 /// Public and optional private key on the given curve. 692 pub struct EcKey<T>; 693 /// A reference to an [`EcKey`]. 694 pub struct EcKeyRef<T>; 695 } 696 697 impl<T> EcKeyRef<T> 698 where 699 T: HasPrivate, 700 { 701 private_key_to_pem! { 702 /// Serializes the private key to a PEM-encoded ECPrivateKey structure. 703 /// 704 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 705 #[corresponds(PEM_write_bio_ECPrivateKey)] 706 private_key_to_pem, 707 /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. 708 /// 709 /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. 710 #[corresponds(PEM_write_bio_ECPrivateKey)] 711 private_key_to_pem_passphrase, 712 ffi::PEM_write_bio_ECPrivateKey 713 } 714 715 to_der! { 716 /// Serializes the private key into a DER-encoded ECPrivateKey structure. 717 #[corresponds(i2d_ECPrivateKey)] 718 private_key_to_der, 719 ffi::i2d_ECPrivateKey 720 } 721 722 /// Returns the private key value. 723 #[corresponds(EC_KEY_get0_private_key)] private_key(&self) -> &BigNumRef724 pub fn private_key(&self) -> &BigNumRef { 725 unsafe { 726 let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); 727 BigNumRef::from_const_ptr(ptr) 728 } 729 } 730 } 731 732 impl<T> EcKeyRef<T> 733 where 734 T: HasPublic, 735 { 736 /// Returns the public key. 737 #[corresponds(EC_KEY_get0_public_key)] public_key(&self) -> &EcPointRef738 pub fn public_key(&self) -> &EcPointRef { 739 unsafe { 740 let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); 741 EcPointRef::from_const_ptr(ptr) 742 } 743 } 744 745 to_pem! { 746 /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. 747 /// 748 /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. 749 #[corresponds(PEM_write_bio_EC_PUBKEY)] 750 public_key_to_pem, 751 ffi::PEM_write_bio_EC_PUBKEY 752 } 753 754 to_der! { 755 /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. 756 #[corresponds(i2d_EC_PUBKEY)] 757 public_key_to_der, 758 ffi::i2d_EC_PUBKEY 759 } 760 } 761 762 impl<T> EcKeyRef<T> 763 where 764 T: HasParams, 765 { 766 /// Returns the key's group. 767 #[corresponds(EC_KEY_get0_group)] group(&self) -> &EcGroupRef768 pub fn group(&self) -> &EcGroupRef { 769 unsafe { 770 let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); 771 EcGroupRef::from_const_ptr(ptr) 772 } 773 } 774 775 /// Checks the key for validity. 776 #[corresponds(EC_KEY_check_key)] check_key(&self) -> Result<(), ErrorStack>777 pub fn check_key(&self) -> Result<(), ErrorStack> { 778 unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } 779 } 780 } 781 782 impl<T> ToOwned for EcKeyRef<T> { 783 type Owned = EcKey<T>; 784 to_owned(&self) -> EcKey<T>785 fn to_owned(&self) -> EcKey<T> { 786 unsafe { 787 let r = ffi::EC_KEY_up_ref(self.as_ptr()); 788 assert!(r == 1); 789 EcKey::from_ptr(self.as_ptr()) 790 } 791 } 792 } 793 794 impl EcKey<Params> { 795 /// Constructs an `EcKey` corresponding to a known curve. 796 /// 797 /// It will not have an associated public or private key. This kind of key is primarily useful 798 /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. 799 #[corresponds(EC_KEY_new_by_curve_name)] from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack>800 pub fn from_curve_name(nid: Nid) -> Result<EcKey<Params>, ErrorStack> { 801 unsafe { 802 init(); 803 cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) 804 } 805 } 806 807 /// Constructs an `EcKey` corresponding to a curve. 808 #[corresponds(EC_KEY_set_group)] from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack>809 pub fn from_group(group: &EcGroupRef) -> Result<EcKey<Params>, ErrorStack> { 810 unsafe { 811 cvt_p(ffi::EC_KEY_new()) 812 .map(|p| EcKey::from_ptr(p)) 813 .and_then(|key| { 814 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 815 }) 816 } 817 } 818 } 819 820 impl EcKey<Public> { 821 /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`. 822 /// 823 /// This will only have the associated `public_key`. 824 /// 825 /// # Example 826 /// 827 /// ``` 828 /// # fn main() -> Result<(), Box<dyn std::error::Error>> { 829 /// use openssl::bn::BigNumContext; 830 /// use openssl::ec::*; 831 /// use openssl::nid::Nid; 832 /// use openssl::pkey::PKey; 833 /// 834 /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?; 835 /// let mut ctx = BigNumContext::new()?; 836 /// 837 /// // get bytes from somewhere 838 /// let public_key = // ... 839 /// # EcKey::generate(&group)?.public_key().to_bytes(&group, 840 /// # PointConversionForm::COMPRESSED, &mut ctx)?; 841 /// 842 /// // create an EcKey from the binary form of a EcPoint 843 /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?; 844 /// let key = EcKey::from_public_key(&group, &point)?; 845 /// key.check_key()?; 846 /// # Ok(()) } 847 /// ``` 848 #[corresponds(EC_KEY_set_public_key)] from_public_key( group: &EcGroupRef, public_key: &EcPointRef, ) -> Result<EcKey<Public>, ErrorStack>849 pub fn from_public_key( 850 group: &EcGroupRef, 851 public_key: &EcPointRef, 852 ) -> Result<EcKey<Public>, ErrorStack> { 853 unsafe { 854 cvt_p(ffi::EC_KEY_new()) 855 .map(|p| EcKey::from_ptr(p)) 856 .and_then(|key| { 857 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 858 }) 859 .and_then(|key| { 860 cvt(ffi::EC_KEY_set_public_key( 861 key.as_ptr(), 862 public_key.as_ptr(), 863 )) 864 .map(|_| key) 865 }) 866 } 867 } 868 869 /// Constructs a public key from its affine coordinates. 870 #[corresponds(EC_KEY_set_public_key_affine_coordinates)] from_public_key_affine_coordinates( group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ) -> Result<EcKey<Public>, ErrorStack>871 pub fn from_public_key_affine_coordinates( 872 group: &EcGroupRef, 873 x: &BigNumRef, 874 y: &BigNumRef, 875 ) -> Result<EcKey<Public>, ErrorStack> { 876 unsafe { 877 cvt_p(ffi::EC_KEY_new()) 878 .map(|p| EcKey::from_ptr(p)) 879 .and_then(|key| { 880 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 881 }) 882 .and_then(|key| { 883 cvt(ffi::EC_KEY_set_public_key_affine_coordinates( 884 key.as_ptr(), 885 x.as_ptr(), 886 y.as_ptr(), 887 )) 888 .map(|_| key) 889 }) 890 } 891 } 892 893 from_pem! { 894 /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. 895 /// 896 /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. 897 #[corresponds(PEM_read_bio_EC_PUBKEY)] 898 public_key_from_pem, 899 EcKey<Public>, 900 ffi::PEM_read_bio_EC_PUBKEY 901 } 902 903 from_der! { 904 /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. 905 #[corresponds(d2i_EC_PUBKEY)] 906 public_key_from_der, 907 EcKey<Public>, 908 ffi::d2i_EC_PUBKEY 909 } 910 } 911 912 impl EcKey<Private> { 913 /// Generates a new public/private key pair on the specified curve. 914 /// 915 /// # Examples 916 /// 917 /// ``` 918 /// # fn main() -> Result<(), Box<dyn std::error::Error>> { 919 /// use openssl::bn::BigNumContext; 920 /// use openssl::nid::Nid; 921 /// use openssl::ec::{EcGroup, EcKey, PointConversionForm}; 922 /// 923 /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve 924 /// let group = EcGroup::from_curve_name(nid)?; 925 /// let key = EcKey::generate(&group)?; 926 /// 927 /// let mut ctx = BigNumContext::new()?; 928 /// 929 /// let public_key = &key.public_key().to_bytes( 930 /// &group, 931 /// PointConversionForm::COMPRESSED, 932 /// &mut ctx, 933 /// )?; 934 /// assert_eq!(public_key.len(), 33); 935 /// assert_ne!(public_key[0], 0x04); 936 /// 937 /// let private_key = key.private_key().to_vec(); 938 /// assert!(private_key.len() >= 31); 939 /// # Ok(()) } 940 /// ``` 941 #[corresponds(EC_KEY_generate_key)] generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack>942 pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> { 943 unsafe { 944 cvt_p(ffi::EC_KEY_new()) 945 .map(|p| EcKey::from_ptr(p)) 946 .and_then(|key| { 947 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 948 }) 949 .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) 950 } 951 } 952 953 /// Constructs an public/private key pair given a curve, a private key and a public key point. 954 #[corresponds(EC_KEY_set_private_key)] from_private_components( group: &EcGroupRef, private_number: &BigNumRef, public_key: &EcPointRef, ) -> Result<EcKey<Private>, ErrorStack>955 pub fn from_private_components( 956 group: &EcGroupRef, 957 private_number: &BigNumRef, 958 public_key: &EcPointRef, 959 ) -> Result<EcKey<Private>, ErrorStack> { 960 unsafe { 961 cvt_p(ffi::EC_KEY_new()) 962 .map(|p| EcKey::from_ptr(p)) 963 .and_then(|key| { 964 cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) 965 }) 966 .and_then(|key| { 967 cvt(ffi::EC_KEY_set_private_key( 968 key.as_ptr(), 969 private_number.as_ptr(), 970 )) 971 .map(|_| key) 972 }) 973 .and_then(|key| { 974 cvt(ffi::EC_KEY_set_public_key( 975 key.as_ptr(), 976 public_key.as_ptr(), 977 )) 978 .map(|_| key) 979 }) 980 } 981 } 982 983 private_key_from_pem! { 984 /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. 985 /// 986 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 987 #[corresponds(PEM_read_bio_ECPrivateKey)] 988 private_key_from_pem, 989 990 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 991 /// 992 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 993 #[corresponds(PEM_read_bio_ECPrivateKey)] 994 private_key_from_pem_passphrase, 995 996 /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. 997 /// 998 /// The callback should fill the password into the provided buffer and return its length. 999 /// 1000 /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. 1001 #[corresponds(PEM_read_bio_ECPrivateKey)] 1002 private_key_from_pem_callback, 1003 EcKey<Private>, 1004 ffi::PEM_read_bio_ECPrivateKey 1005 } 1006 1007 from_der! { 1008 /// Decodes a DER-encoded elliptic curve private key structure. 1009 #[corresponds(d2i_ECPrivateKey)] 1010 private_key_from_der, 1011 EcKey<Private>, 1012 ffi::d2i_ECPrivateKey 1013 } 1014 1015 /// Decodes a DER-encoded elliptic curve private key structure for the specified curve. 1016 #[corresponds(EC_KEY_parse_private_key)] 1017 #[cfg(boringssl)] private_key_from_der_for_group( der: &[u8], group: &EcGroupRef, ) -> Result<EcKey<Private>, ErrorStack>1018 pub fn private_key_from_der_for_group( 1019 der: &[u8], 1020 group: &EcGroupRef, 1021 ) -> Result<EcKey<Private>, ErrorStack> { 1022 unsafe { 1023 let mut cbs = ffi::CBS { 1024 data: der.as_ptr(), 1025 len: der.len(), 1026 }; 1027 cvt_p(ffi::EC_KEY_parse_private_key( 1028 &mut cbs as *mut ffi::CBS, 1029 group.as_ptr(), 1030 )) 1031 .map(|p| EcKey::from_ptr(p)) 1032 } 1033 } 1034 } 1035 1036 impl<T> Clone for EcKey<T> { clone(&self) -> EcKey<T>1037 fn clone(&self) -> EcKey<T> { 1038 (**self).to_owned() 1039 } 1040 } 1041 1042 impl<T> fmt::Debug for EcKey<T> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1043 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1044 write!(f, "EcKey") 1045 } 1046 } 1047 1048 #[cfg(test)] 1049 mod test { 1050 use hex::FromHex; 1051 1052 use super::*; 1053 use crate::bn::{BigNum, BigNumContext}; 1054 use crate::nid::Nid; 1055 1056 #[test] key_new_by_curve_name()1057 fn key_new_by_curve_name() { 1058 EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1059 } 1060 1061 #[test] generate()1062 fn generate() { 1063 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1064 EcKey::generate(&group).unwrap(); 1065 } 1066 1067 #[test] ec_group_from_components()1068 fn ec_group_from_components() { 1069 // parameters are from secp256r1 1070 let p = BigNum::from_hex_str( 1071 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 1072 ) 1073 .unwrap(); 1074 let a = BigNum::from_hex_str( 1075 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 1076 ) 1077 .unwrap(); 1078 let b = BigNum::from_hex_str( 1079 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 1080 ) 1081 .unwrap(); 1082 let mut ctx = BigNumContext::new().unwrap(); 1083 1084 let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); 1085 } 1086 1087 #[test] ec_point_set_affine()1088 fn ec_point_set_affine() { 1089 // parameters are from secp256r1 1090 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1091 let mut ctx = BigNumContext::new().unwrap(); 1092 let mut gen_point = EcPoint::new(&group).unwrap(); 1093 let gen_x = BigNum::from_hex_str( 1094 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 1095 ) 1096 .unwrap(); 1097 let gen_y = BigNum::from_hex_str( 1098 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 1099 ) 1100 .unwrap(); 1101 gen_point 1102 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) 1103 .unwrap(); 1104 assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap()); 1105 } 1106 1107 #[test] ec_group_set_generator()1108 fn ec_group_set_generator() { 1109 // parameters are from secp256r1 1110 let mut ctx = BigNumContext::new().unwrap(); 1111 let p = BigNum::from_hex_str( 1112 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 1113 ) 1114 .unwrap(); 1115 let a = BigNum::from_hex_str( 1116 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 1117 ) 1118 .unwrap(); 1119 let b = BigNum::from_hex_str( 1120 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 1121 ) 1122 .unwrap(); 1123 1124 let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); 1125 1126 let mut gen_point = EcPoint::new(&group).unwrap(); 1127 let gen_x = BigNum::from_hex_str( 1128 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 1129 ) 1130 .unwrap(); 1131 let gen_y = BigNum::from_hex_str( 1132 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 1133 ) 1134 .unwrap(); 1135 gen_point 1136 .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) 1137 .unwrap(); 1138 1139 let order = BigNum::from_hex_str( 1140 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1141 ) 1142 .unwrap(); 1143 let cofactor = BigNum::from_hex_str("01").unwrap(); 1144 group.set_generator(gen_point, order, cofactor).unwrap(); 1145 let mut constructed_order = BigNum::new().unwrap(); 1146 group.order(&mut constructed_order, &mut ctx).unwrap(); 1147 1148 let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1149 let mut named_order = BigNum::new().unwrap(); 1150 named_group.order(&mut named_order, &mut ctx).unwrap(); 1151 1152 assert_eq!( 1153 constructed_order.ucmp(&named_order), 1154 std::cmp::Ordering::Equal 1155 ); 1156 } 1157 1158 #[test] cofactor()1159 fn cofactor() { 1160 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1161 let mut ctx = BigNumContext::new().unwrap(); 1162 let mut cofactor = BigNum::new().unwrap(); 1163 group.cofactor(&mut cofactor, &mut ctx).unwrap(); 1164 let one = BigNum::from_u32(1).unwrap(); 1165 assert_eq!(cofactor, one); 1166 } 1167 1168 #[test] 1169 #[allow(clippy::redundant_clone)] dup()1170 fn dup() { 1171 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1172 let key = EcKey::generate(&group).unwrap(); 1173 drop(key.clone()); 1174 } 1175 1176 #[test] point_new()1177 fn point_new() { 1178 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1179 EcPoint::new(&group).unwrap(); 1180 } 1181 1182 #[test] point_bytes()1183 fn point_bytes() { 1184 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1185 let key = EcKey::generate(&group).unwrap(); 1186 let point = key.public_key(); 1187 let mut ctx = BigNumContext::new().unwrap(); 1188 let bytes = point 1189 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1190 .unwrap(); 1191 let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1192 assert!(point.eq(&group, &point2, &mut ctx).unwrap()); 1193 } 1194 1195 #[test] 1196 #[cfg(not(boringssl))] point_hex_str()1197 fn point_hex_str() { 1198 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1199 let key = EcKey::generate(&group).unwrap(); 1200 let point = key.public_key(); 1201 let mut ctx = BigNumContext::new().unwrap(); 1202 let hex = point 1203 .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx) 1204 .unwrap(); 1205 let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap(); 1206 assert!(point.eq(&group, &point2, &mut ctx).unwrap()); 1207 } 1208 1209 #[test] point_owned()1210 fn point_owned() { 1211 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1212 let key = EcKey::generate(&group).unwrap(); 1213 let point = key.public_key(); 1214 let owned = point.to_owned(&group).unwrap(); 1215 let mut ctx = BigNumContext::new().unwrap(); 1216 assert!(owned.eq(&group, point, &mut ctx).unwrap()); 1217 } 1218 1219 #[test] mul_generator()1220 fn mul_generator() { 1221 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1222 let key = EcKey::generate(&group).unwrap(); 1223 let mut ctx = BigNumContext::new().unwrap(); 1224 let mut public_key = EcPoint::new(&group).unwrap(); 1225 public_key 1226 .mul_generator(&group, key.private_key(), &ctx) 1227 .unwrap(); 1228 assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); 1229 } 1230 1231 #[test] generator()1232 fn generator() { 1233 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1234 let gen = group.generator(); 1235 let one = BigNum::from_u32(1).unwrap(); 1236 let mut ctx = BigNumContext::new().unwrap(); 1237 let mut ecp = EcPoint::new(&group).unwrap(); 1238 ecp.mul_generator(&group, &one, &ctx).unwrap(); 1239 assert!(ecp.eq(&group, gen, &mut ctx).unwrap()); 1240 } 1241 1242 #[test] key_from_public_key()1243 fn key_from_public_key() { 1244 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1245 let key = EcKey::generate(&group).unwrap(); 1246 let mut ctx = BigNumContext::new().unwrap(); 1247 let bytes = key 1248 .public_key() 1249 .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) 1250 .unwrap(); 1251 1252 drop(key); 1253 let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); 1254 let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); 1255 assert!(ec_key.check_key().is_ok()); 1256 } 1257 1258 #[test] key_from_private_components()1259 fn key_from_private_components() { 1260 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1261 let key = EcKey::generate(&group).unwrap(); 1262 1263 let dup_key = 1264 EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); 1265 dup_key.check_key().unwrap(); 1266 1267 assert!(key.private_key() == dup_key.private_key()); 1268 } 1269 1270 #[test] key_from_affine_coordinates()1271 fn key_from_affine_coordinates() { 1272 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1273 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1274 .unwrap(); 1275 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1276 .unwrap(); 1277 1278 let xbn = BigNum::from_slice(&x).unwrap(); 1279 let ybn = BigNum::from_slice(&y).unwrap(); 1280 1281 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1282 assert!(ec_key.check_key().is_ok()); 1283 } 1284 1285 #[cfg(any(ossl111, boringssl, libressl350))] 1286 #[test] get_affine_coordinates()1287 fn get_affine_coordinates() { 1288 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1289 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1290 .unwrap(); 1291 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1292 .unwrap(); 1293 1294 let xbn = BigNum::from_slice(&x).unwrap(); 1295 let ybn = BigNum::from_slice(&y).unwrap(); 1296 1297 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1298 1299 let mut xbn2 = BigNum::new().unwrap(); 1300 let mut ybn2 = BigNum::new().unwrap(); 1301 let mut ctx = BigNumContext::new().unwrap(); 1302 let ec_key_pk = ec_key.public_key(); 1303 ec_key_pk 1304 .affine_coordinates(&group, &mut xbn2, &mut ybn2, &mut ctx) 1305 .unwrap(); 1306 assert_eq!(xbn2, xbn); 1307 assert_eq!(ybn2, ybn); 1308 } 1309 1310 #[test] get_affine_coordinates_gfp()1311 fn get_affine_coordinates_gfp() { 1312 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1313 let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") 1314 .unwrap(); 1315 let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") 1316 .unwrap(); 1317 1318 let xbn = BigNum::from_slice(&x).unwrap(); 1319 let ybn = BigNum::from_slice(&y).unwrap(); 1320 1321 let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); 1322 1323 let mut xbn2 = BigNum::new().unwrap(); 1324 let mut ybn2 = BigNum::new().unwrap(); 1325 let mut ctx = BigNumContext::new().unwrap(); 1326 let ec_key_pk = ec_key.public_key(); 1327 ec_key_pk 1328 .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) 1329 .unwrap(); 1330 assert_eq!(xbn2, xbn); 1331 assert_eq!(ybn2, ybn); 1332 } 1333 1334 #[test] is_infinity()1335 fn is_infinity() { 1336 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1337 let mut ctx = BigNumContext::new().unwrap(); 1338 let g = group.generator(); 1339 assert!(!g.is_infinity(&group)); 1340 1341 let mut order = BigNum::new().unwrap(); 1342 group.order(&mut order, &mut ctx).unwrap(); 1343 let mut inf = EcPoint::new(&group).unwrap(); 1344 inf.mul_generator(&group, &order, &ctx).unwrap(); 1345 assert!(inf.is_infinity(&group)); 1346 } 1347 1348 #[test] 1349 #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] is_on_curve()1350 fn is_on_curve() { 1351 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1352 let mut ctx = BigNumContext::new().unwrap(); 1353 let g = group.generator(); 1354 assert!(g.is_on_curve(&group, &mut ctx).unwrap()); 1355 1356 let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); 1357 assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); 1358 } 1359 1360 #[test] 1361 #[cfg(any(boringssl, ossl111, libressl350))] asn1_flag()1362 fn asn1_flag() { 1363 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 1364 let flag = group.asn1_flag(); 1365 assert_eq!(flag, Asn1Flag::NAMED_CURVE); 1366 } 1367 } 1368