Skip to content

Commit

Permalink
Add EC signature verification (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
ubamrein authored and ramosbugs committed Nov 25, 2020
1 parent f0031cf commit f61b108
Show file tree
Hide file tree
Showing 5 changed files with 339 additions and 11 deletions.
74 changes: 66 additions & 8 deletions src/core/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ring::signature as ring_signature;
use crate::types::Base64UrlEncodedBytes;
use crate::{JsonWebKey, SignatureVerificationError, SigningError};

use super::{CoreJsonWebKey, CoreJsonWebKeyType};
use super::{jwk::CoreJsonCurveType, CoreJsonWebKey, CoreJsonWebKeyType};

use std::ops::Deref;

Expand Down Expand Up @@ -46,14 +46,45 @@ fn rsa_public_key(
) -> Result<(&Base64UrlEncodedBytes, &Base64UrlEncodedBytes), String> {
if *key.key_type() != CoreJsonWebKeyType::RSA {
Err("RSA key required".to_string())
} else if let Some(n) = key.n.as_ref() {
if let Some(e) = key.e.as_ref() {
Ok((n, e))
} else {
Err("RSA exponent `e` is missing".to_string())
}
} else {
Err("RSA modulus `n` is missing".to_string())
let n = key
.n
.as_ref()
.ok_or_else(|| "RSA modulus `n` is missing".to_string())?;
let e = key
.e
.as_ref()
.ok_or_else(|| "RSA exponent `e` is missing".to_string())?;
Ok((n, e))
}
}

fn ec_public_key(
key: &CoreJsonWebKey,
) -> Result<
(
&Base64UrlEncodedBytes,
&Base64UrlEncodedBytes,
&CoreJsonCurveType,
),
String,
> {
if *key.key_type() != CoreJsonWebKeyType::EllipticCurve {
Err("EC key required".to_string())
} else {
let x = key
.x
.as_ref()
.ok_or_else(|| "EC `x` part is missing".to_string())?;
let y = key
.y
.as_ref()
.ok_or_else(|| "EC `y` part is missing".to_string())?;
let crv = key
.crv
.as_ref()
.ok_or_else(|| "EC `crv` part is missing".to_string())?;
Ok((x, y, crv))
}
}

Expand All @@ -73,3 +104,30 @@ pub fn verify_rsa_signature(
.verify(params, msg, signature)
.map_err(|_| SignatureVerificationError::CryptoError("bad signature".to_string()))
}
/// According to RFC5480, Section-2.2 implementations of Elliptic Curve Cryptography MUST support the uncompressed form.
/// The first octet of the octet string indicates whether the uncompressed or compressed form is used. For the uncompressed
/// form, the first octet has to be 0x04.
/// According to https://briansmith.org/rustdoc/ring/signature/index.html#ecdsa__fixed-details-fixed-length-pkcs11-style-ecdsa-signatures,
/// to recover the X and Y coordinates from an octet string, the Octet-String-To-Elliptic-Curve-Point Conversion
/// is used (Section 2.3.4 of https://www.secg.org/sec1-v2.pdf).
pub fn verify_ec_signature(
key: &CoreJsonWebKey,
params: &'static ring_signature::EcdsaVerificationAlgorithm,
msg: &[u8],
signature: &[u8],
) -> Result<(), SignatureVerificationError> {
let (x, y, crv) = ec_public_key(&key).map_err(SignatureVerificationError::InvalidKey)?;
if *crv == CoreJsonCurveType::P521 {
return Err(SignatureVerificationError::UnsupportedAlg(
"P521".to_string(),
));
}
let mut pk = vec![0x04];
pk.extend(x.deref());
pk.extend(y.deref());
let public_key = ring_signature::UnparsedPublicKey::new(params, pk);
public_key
.verify(msg, signature)
.map_err(|_| SignatureVerificationError::CryptoError("EC Signature was wrong".to_string()))
}
Loading

0 comments on commit f61b108

Please sign in to comment.