Skip to content

Commit

Permalink
Migrate x25519 to use rust-openssl
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed Mar 20, 2023
1 parent 7a51706 commit b259544
Show file tree
Hide file tree
Showing 13 changed files with 369 additions and 153 deletions.
1 change: 0 additions & 1 deletion src/_cffi_src/openssl/nid.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
static const int NID_undef;
static const int NID_aes_256_cbc;
static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
static const int NID_X25519;
static const int NID_X448;
static const int NID_ED25519;
static const int NID_ED448;
Expand Down
38 changes: 10 additions & 28 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@
_X448PrivateKey,
_X448PublicKey,
)
from cryptography.hazmat.backends.openssl.x25519 import (
_X25519PrivateKey,
_X25519PublicKey,
)
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding
Expand Down Expand Up @@ -719,7 +716,9 @@ def _evp_pkey_to_private_key(
# EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _X448PrivateKey(self, evp_pkey)
elif key_type == self._lib.EVP_PKEY_X25519:
return _X25519PrivateKey(self, evp_pkey)
return rust_openssl.x25519.private_key_from_ptr(
int(self._ffi.cast("intptr_t", evp_pkey))
)
elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
# EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _Ed448PrivateKey(self, evp_pkey)
Expand Down Expand Up @@ -776,7 +775,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes:
# EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _X448PublicKey(self, evp_pkey)
elif key_type == self._lib.EVP_PKEY_X25519:
return _X25519PublicKey(self, evp_pkey)
return rust_openssl.x25519.public_key_from_ptr(
int(self._ffi.cast("intptr_t", evp_pkey))
)
elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
# EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _Ed448PublicKey(self, evp_pkey)
Expand Down Expand Up @@ -1865,30 +1866,12 @@ def dh_x942_serialization_supported(self) -> bool:
return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1

def x25519_load_public_bytes(self, data: bytes) -> x25519.X25519PublicKey:
if len(data) != 32:
raise ValueError("An X25519 public key is 32 bytes long")

data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
self._lib.NID_X25519, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _X25519PublicKey(self, evp_pkey)
return rust_openssl.x25519.from_public_bytes(data)

def x25519_load_private_bytes(
self, data: bytes
) -> x25519.X25519PrivateKey:
if len(data) != 32:
raise ValueError("An X25519 private key is 32 bytes long")

data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
self._lib.NID_X25519, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
return _X25519PrivateKey(self, evp_pkey)
return rust_openssl.x25519.from_private_bytes(bytes(memoryview(data)))

def _evp_pkey_keygen_gc(self, nid):
evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL)
Expand All @@ -1904,8 +1887,7 @@ def _evp_pkey_keygen_gc(self, nid):
return evp_pkey

def x25519_generate_key(self) -> x25519.X25519PrivateKey:
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519)
return _X25519PrivateKey(self, evp_pkey)
return rust_openssl.x25519.generate_key()

def x25519_supported(self) -> bool:
if self._fips_enabled:
Expand Down
120 changes: 0 additions & 120 deletions src/cryptography/hazmat/backends/openssl/x25519.py

This file was deleted.

4 changes: 4 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@

import typing

from cryptography.hazmat.bindings._rust.openssl import x25519

__all__ = ["openssl_version", "raise_openssl_error", "x25519"]

def openssl_version() -> int: ...
def raise_openssl_error() -> typing.NoReturn: ...
14 changes: 14 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

from cryptography.hazmat.primitives.asymmetric import x25519

class X25519PrivateKey: ...
class X25519PublicKey: ...

def generate_key() -> x25519.X25519PrivateKey: ...
def private_key_from_ptr(ptr: int) -> x25519.X25519PrivateKey: ...
def public_key_from_ptr(ptr: int) -> x25519.X25519PublicKey: ...
def from_private_bytes(data: bytes) -> x25519.X25519PrivateKey: ...
def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ...
11 changes: 11 additions & 0 deletions src/cryptography/hazmat/primitives/asymmetric/x25519.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import abc

from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import _serialization


Expand Down Expand Up @@ -42,6 +43,11 @@ def public_bytes_raw(self) -> bytes:
)


# For LibreSSL
if hasattr(rust_openssl, "x25519"):
X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey)


class X25519PrivateKey(metaclass=abc.ABCMeta):
@classmethod
def generate(cls) -> "X25519PrivateKey":
Expand Down Expand Up @@ -99,3 +105,8 @@ def exchange(self, peer_public_key: X25519PublicKey) -> bytes:
"""
Performs a key exchange operation using the provided peer's public key.
"""


# For LibreSSL
if hasattr(rust_openssl, "x25519"):
X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey)
4 changes: 2 additions & 2 deletions src/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ chrono = { version = "0.4.24", default-features = false, features = ["alloc", "c
ouroboros = "0.15"
openssl = "0.10.47"
openssl-sys = "0.9.72"
foreign-types-shared = "0.1"

[build-dependencies]
cc = "1.0.72"
Expand Down
13 changes: 12 additions & 1 deletion src/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::io::Write;
use std::path::Path;
use std::process::{Command, Stdio};

#[allow(clippy::unusual_byte_groupings)]
fn main() {
let target = env::var("TARGET").unwrap();
let openssl_static = env::var("OPENSSL_STATIC")
Expand Down Expand Up @@ -57,7 +58,8 @@ fn main() {
.include(python_include)
.include(openssl_include)
.flag_if_supported("-Wconversion")
.flag_if_supported("-Wno-error=sign-conversion");
.flag_if_supported("-Wno-error=sign-conversion")
.flag_if_supported("-Wno-unused-parameter");

// Enable abi3 mode if we're not using PyPy.
if python_impl != "PyPy" {
Expand All @@ -70,6 +72,15 @@ fn main() {
}

build.compile("_openssl.a");

if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") {
let version = u64::from_str_radix(&version, 16).unwrap();

println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_LIBRESSL");
if version >= 0x3_07_00_00_0 {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER")
}
}
}

/// Run a python script using the specified interpreter binary.
Expand Down
13 changes: 13 additions & 0 deletions src/rust/src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This file is dual licensed under the terms of the Apache License, Version
// 2.0, and the BSD License. See the LICENSE file in the root of this repository
// for complete details.

#[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))]
pub(crate) mod x25519;

pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> {
#[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))]
module.add_submodule(x25519::create_module(module.py())?)?;

Ok(())
}

0 comments on commit b259544

Please sign in to comment.