Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate x25519 to use rust-openssl #7933

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
37 changes: 9 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,6 @@
_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
Expand Down Expand Up @@ -715,7 +711,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 @@ -772,7 +770,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 @@ -1860,30 +1860,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(data)

def _evp_pkey_keygen_gc(self, nid):
evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL)
Expand All @@ -1899,8 +1881,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,6 +4,10 @@

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: ...
def capture_error_stack() -> typing.List[OpenSSLError]: ...
Expand Down
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: ...
21 changes: 13 additions & 8 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 All @@ -32,14 +33,17 @@ def public_bytes(
The serialized bytes of the public key.
"""

@abc.abstractmethod
def public_bytes_raw(self) -> bytes:
"""
The raw bytes of the public key.
Equivalent to public_bytes(Raw, Raw).
"""
return self.public_bytes(
_serialization.Encoding.Raw, _serialization.PublicFormat.Raw
)


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


class X25519PrivateKey(metaclass=abc.ABCMeta):
Expand Down Expand Up @@ -83,19 +87,20 @@ def private_bytes(
The serialized bytes of the private key.
"""

@abc.abstractmethod
def private_bytes_raw(self) -> bytes:
"""
The raw bytes of the private key.
Equivalent to private_bytes(Raw, Raw, NoEncryption()).
"""
return self.private_bytes(
_serialization.Encoding.Raw,
_serialization.PrivateFormat.Raw,
_serialization.NoEncryption(),
)

@abc.abstractmethod
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)
1 change: 1 addition & 0 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.48"
openssl-sys = "0.9.72"
foreign-types-shared = "0.1"

[build-dependencies]
cc = "1.0.72"
Expand Down
10 changes: 10 additions & 0 deletions 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)]
alex marked this conversation as resolved.
Show resolved Hide resolved
fn main() {
let target = env::var("TARGET").unwrap();
let openssl_static = env::var("OPENSSL_STATIC")
Expand Down Expand Up @@ -71,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(())
}