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

[DRAFT] unstable API for ML-DSA #690

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions aws-lc-rs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,32 @@ coverage:
coverage-fips:
cargo llvm-cov --features "${AWS_LC_RS_COV_EXTRA_FEATURES},fips" --no-fail-fast --fail-under-lines 95 --ignore-filename-regex "aws-lc(-fips|)-sys/*" --lcov --output-path lcov.info

test: export AWS_LC_RS_DISABLE_SLOW_TESTS = 1
test:
cargo test --all-targets
cargo test --all-targets --features unstable
cargo test --release --all-targets
cargo test --release --all-targets --features bindgen,unstable
cargo test --release --all-targets --features fips,unstable
cargo test --no-default-features --all-targets --features fips,unstable
cargo test --release --all-targets --features fips,bindgen,unstable
cargo test --no-default-features --all-targets --features aws-lc-sys
cargo test --no-default-features --all-targets --features aws-lc-sys,unstable
cargo test --no-default-features --all-targets --features aws-lc-sys,ring-sig-verify,unstable
cargo test --no-default-features --all-targets --features aws-lc-sys,ring-io,unstable
cargo test --no-default-features --all-targets --features aws-lc-sys,alloc,unstable
cargo test --no-default-features --all-targets --features fips
cargo test --no-default-features --all-targets --features fips,unstable
cargo test --no-default-features --all-targets --features aws-lc-sys,ring-sig-verify
cargo test --no-default-features --all-targets --features aws-lc-sys,ring-io
cargo test --no-default-features --all-targets --features aws-lc-sys,alloc

msrv:
cargo msrv verify

clippy:
cargo +nightly clippy --all-targets --features bindgen,fips,unstable -- -W clippy::all -W clippy::pedantic

clippy-fix:
clippy-fips-fix:
cargo +nightly clippy --all-targets --features bindgen,fips,unstable --fix --allow-dirty -- -W clippy::all -W clippy::pedantic

clippy-fix:
cargo +nightly clippy --all-targets --features bindgen,unstable --fix --allow-dirty -- -W clippy::all -W clippy::pedantic

ci: format clippy msrv test coverage api-diff-pub

readme:
Expand Down
14 changes: 0 additions & 14 deletions aws-lc-rs/src/bn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,6 @@ impl TryFrom<&[u8]> for LcPtr<BIGNUM> {
}
}

impl TryFrom<u64> for LcPtr<BIGNUM> {
type Error = ();

fn try_from(value: u64) -> Result<Self, Self::Error> {
unsafe {
let mut bn = LcPtr::new(BN_new())?;
if 1 != BN_set_u64(*bn.as_mut(), value) {
return Err(());
}
Ok(bn)
}
}
}

impl TryFrom<&[u8]> for DetachableLcPtr<BIGNUM> {
type Error = ();

Expand Down
4 changes: 1 addition & 3 deletions aws-lc-rs/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ pub(crate) mod signature;
const ELEM_MAX_BITS: usize = 521;
pub(crate) const ELEM_MAX_BYTES: usize = (ELEM_MAX_BITS + 7) / 8;

pub(crate) const SCALAR_MAX_BYTES: usize = ELEM_MAX_BYTES;

/// The maximum length, in bytes, of an encoded public key.
pub(crate) const PUBLIC_KEY_MAX_LEN: usize = 1 + (2 * ELEM_MAX_BYTES);

Expand Down Expand Up @@ -62,7 +60,7 @@ pub(crate) fn verify_evp_key_nid(
}

#[inline]
pub(crate) fn validate_evp_key(
pub(crate) fn validate_ec_evp_key(
evp_pkey: &ConstPointer<EVP_PKEY>,
expected_curve_nid: i32,
) -> Result<(), KeyRejected> {
Expand Down
10 changes: 5 additions & 5 deletions aws-lc-rs/src/ec/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::aws_lc::{EVP_PKEY, EVP_PKEY_EC};
use crate::ec::encoding::sec1::parse_sec1_public_point;
use crate::ec::validate_evp_key;
use crate::ec::validate_ec_evp_key;

use crate::error::KeyRejected;
use crate::ptr::LcPtr;
Expand All @@ -23,7 +23,7 @@ pub(crate) mod sec1 {
use crate::cbb::LcCBB;
use crate::ec::{
compressed_public_key_size_bytes, ec_group_from_nid, uncompressed_public_key_size_bytes,
validate_evp_key, KeyRejected,
validate_ec_evp_key, KeyRejected,
};
use crate::error::Unspecified;
use crate::ptr::{ConstPointer, DetachableLcPtr, LcPtr};
Expand Down Expand Up @@ -72,7 +72,7 @@ pub(crate) mod sec1 {

ec_key.detach();

validate_evp_key(&pkey.as_const(), nid)?;
validate_ec_evp_key(&pkey.as_const(), nid)?;

Ok(pkey)
}
Expand Down Expand Up @@ -126,7 +126,7 @@ pub(crate) mod sec1 {
ec_key.detach();

// Validate the EC_KEY before returning it.
validate_evp_key(&pkey.as_const(), expected_curve_nid)?;
validate_ec_evp_key(&pkey.as_const(), expected_curve_nid)?;

Ok(pkey)
}
Expand Down Expand Up @@ -250,5 +250,5 @@ pub(crate) fn parse_ec_public_key(
) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(key_bytes, EVP_PKEY_EC)
.or(parse_sec1_public_point(key_bytes, expected_curve_nid))
.and_then(|key| validate_evp_key(&key.as_const(), expected_curve_nid).map(|()| key))
.and_then(|key| validate_ec_evp_key(&key.as_const(), expected_curve_nid).map(|()| key))
}
4 changes: 2 additions & 2 deletions aws-lc-rs/src/ec/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use core::fmt::{Debug, Formatter};
use crate::ec::evp_key_generate;
use crate::ec::signature::{EcdsaSignatureFormat, EcdsaSigningAlgorithm, PublicKey};
#[cfg(feature = "fips")]
use crate::ec::validate_evp_key;
use crate::ec::validate_ec_evp_key;
#[cfg(not(feature = "fips"))]
use crate::ec::verify_evp_key_nid;

Expand Down Expand Up @@ -97,7 +97,7 @@ impl EcdsaKeyPair {
#[cfg(not(feature = "fips"))]
verify_evp_key_nid(&evp_pkey.as_const(), alg.id.nid())?;
#[cfg(feature = "fips")]
validate_evp_key(&evp_pkey.as_const(), alg.id.nid())?;
validate_ec_evp_key(&evp_pkey.as_const(), alg.id.nid())?;

let key_pair = Self::new(alg, evp_pkey)?;

Expand Down
12 changes: 11 additions & 1 deletion aws-lc-rs/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ generated_encodings!(
PublicKeyX509Der,
Curve25519SeedBin,
Pkcs8V1Der,
Pkcs8V2Der
Pkcs8V2Der,
PqdsaPrivateKeyBin
);

/// Trait for types that can be serialized into a DER format.
Expand All @@ -83,3 +84,12 @@ pub trait AsBigEndian<T> {
/// Returns Unspecified if serialization fails.
fn as_be_bytes(&self) -> Result<T, crate::error::Unspecified>;
}

/// Trait for values that can be serialized into a raw format
pub trait AsRawBytes<T> {
/// Serializes into a raw format.
///
/// # Errors
/// Returns Unspecified if serialization fails.
fn as_raw_bytes(&self) -> Result<T, crate::error::Unspecified>;
}
6 changes: 3 additions & 3 deletions aws-lc-rs/src/evp_pkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::aws_lc::{
EVP_parse_private_key, EVP_parse_public_key, EC_KEY, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_ED25519,
RSA,
};
#[cfg(not(feature = "fips"))]
#[cfg(all(feature = "unstable", not(feature = "fips")))]
use crate::aws_lc::{
EVP_PKEY_pqdsa_new_raw_private_key, EVP_PKEY_pqdsa_new_raw_public_key, EVP_PKEY_PQDSA,
NID_MLDSA44, NID_MLDSA65, NID_MLDSA87,
Expand Down Expand Up @@ -243,7 +243,7 @@ impl LcPtr<EVP_PKEY> {
bytes: &[u8],
evp_pkey_type: c_int,
) -> Result<Self, KeyRejected> {
#[cfg(not(feature = "fips"))]
#[cfg(all(feature = "unstable", not(feature = "fips")))]
if evp_pkey_type == EVP_PKEY_PQDSA {
return match bytes.len() {
2560 => Self::new(unsafe {
Expand All @@ -270,7 +270,7 @@ impl LcPtr<EVP_PKEY> {
bytes: &[u8],
evp_pkey_type: c_int,
) -> Result<Self, KeyRejected> {
#[cfg(not(feature = "fips"))]
#[cfg(all(feature = "unstable", not(feature = "fips")))]
if evp_pkey_type == EVP_PKEY_PQDSA {
return match bytes.len() {
1312 => Self::new(unsafe {
Expand Down
4 changes: 2 additions & 2 deletions aws-lc-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ pub mod iv;
pub mod kdf;
#[allow(clippy::module_name_repetitions)]
pub mod kem;
#[cfg(not(feature = "fips"))]
mod pq;
#[cfg(all(feature = "unstable", not(feature = "fips")))]
mod pqdsa;
mod ptr;
pub mod rsa;
pub mod tls_prf;
Expand Down
100 changes: 0 additions & 100 deletions aws-lc-rs/src/pq.rs
Original file line number Diff line number Diff line change
@@ -1,100 +0,0 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#![allow(unused)]

use crate::aws_lc::{
d2i_PrivateKey, CBB_init, EVP_PKEY_CTX_new_id, EVP_PKEY_CTX_pqdsa_set_params,
EVP_PKEY_get_raw_private_key, EVP_PKEY_get_raw_public_key, EVP_PKEY_new,
EVP_PKEY_pqdsa_new_raw_private_key, EVP_PKEY_pqdsa_new_raw_public_key, EVP_marshal_private_key,
EVP_marshal_public_key, EVP_parse_public_key, CBB, EVP_PKEY, EVP_PKEY_PQDSA,
};
use crate::cbb::LcCBB;
use crate::cbs::build_CBS;
use crate::digest;
use crate::digest::digest_ctx::DigestContext;
use crate::error::{KeyRejected, Unspecified};
use crate::evp_pkey::*;
use crate::fips::indicator_check;
use crate::ptr::LcPtr;
use crate::signature::MAX_LEN;
use std::os::raw::c_int;
use std::ptr::null_mut;

pub(crate) fn evp_key_pqdsa_generate(nid: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
let params_fn = |ctx| {
if 1 == unsafe { EVP_PKEY_CTX_pqdsa_set_params(ctx, nid) } {
Ok(())
} else {
Err(())
}
};
LcPtr::<EVP_PKEY>::generate(EVP_PKEY_PQDSA, Some(params_fn))
}

#[cfg(test)]
mod tests {
use crate::aws_lc::{
EVP_PKEY_cmp, EVP_PKEY, EVP_PKEY_PQDSA, NID_MLDSA44, NID_MLDSA65, NID_MLDSA87,
};
use crate::digest;
use crate::evp_pkey::*;
use crate::hmac::sign;
use crate::pkcs8::Version;
use crate::pq::evp_key_pqdsa_generate;
use crate::ptr::LcPtr;
use std::ffi::c_int;

#[test]
fn test_keygen() {
for nid in [NID_MLDSA44, NID_MLDSA65, NID_MLDSA87] {
let key = evp_key_pqdsa_generate(nid).unwrap();
println!("key size: {:?}", key.key_size_bytes());
test_serialization_for(&key);
test_signing_for(&key);
}
}

fn test_serialization_for(evp_pkey: &LcPtr<EVP_PKEY>) {
let public_buffer = evp_pkey.marshal_rfc5280_public_key().unwrap();
println!("public marshall: {public_buffer:?}");
let key_public =
LcPtr::<EVP_PKEY>::parse_rfc5280_public_key(&public_buffer, EVP_PKEY_PQDSA).unwrap();

let private_buffer = evp_pkey.marshal_rfc5208_private_key(Version::V1).unwrap();
println!("private marshall: {private_buffer:?}");
let key_private =
LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(&private_buffer, EVP_PKEY_PQDSA).unwrap();

let raw_public_buffer = key_public.marshal_raw_public_key().unwrap();
println!("raw public size: {}", raw_public_buffer.len());
let key_public2 =
LcPtr::<EVP_PKEY>::parse_raw_public_key(&raw_public_buffer, EVP_PKEY_PQDSA).unwrap();

assert_eq!(1, unsafe {
EVP_PKEY_cmp(*key_public.as_const(), *key_public2.as_const())
});

let raw_private_buffer = key_private.marshal_raw_private_key().unwrap();
println!("raw private size: {}", raw_private_buffer.len());
let key_private2 =
LcPtr::<EVP_PKEY>::parse_raw_private_key(&raw_private_buffer, EVP_PKEY_PQDSA).unwrap();

// TODO: Currently the public key is not populated
// assert_eq!(1, unsafe {
// EVP_PKEY_cmp(*key_private.as_const(), *key_private2.as_const())
// });
}

fn test_signing_for(evp_pkey: &LcPtr<EVP_PKEY>) {
let message = b"hello world";
let signature = evp_pkey
.sign(message, None, No_EVP_PKEY_CTX_consumer)
.unwrap();
println!("signature size: {}", signature.len());
assert_eq!(signature.len(), evp_pkey.signature_size_bytes());
evp_pkey
.verify(message, None, No_EVP_PKEY_CTX_consumer, &signature)
.unwrap();
println!("verified: {signature:?}");
}
}
Loading
Loading