From a504b58d627256f65a3e3a19463cd959dc98ade9 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sun, 28 Jan 2018 15:22:32 -0800 Subject: [PATCH] [BROKEN] Working towards ECDSA support. --- src/error.rs | 20 +++++++-- src/lib.rs | 41 +++++++++--------- src/publickey.rs | 105 ++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 129 insertions(+), 37 deletions(-) diff --git a/src/error.rs b/src/error.rs index b30ad35..93db02e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,13 +1,15 @@ -use simple_asn1::ASN1DecodeErr; +use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr}; use simple_dsa::DSADecodeError; use simple_dsa::dsa::DSAError; +use simple_dsa::ecdsa::ECDSAError; use simple_rsa::RSAError; /// The error type for parsing and validating an X.509 certificate. #[derive(Debug)] pub enum X509ParseError { - ASN1DecodeError(ASN1DecodeErr), + ASN1DecodeError(ASN1DecodeErr), ASN1EncodeError(ASN1EncodeErr), RSAError(RSAError), DSAError(DSAError), DSASigParseError(DSADecodeError), + ECDSAError(ECDSAError), RSASignatureWrong, DSASignatureWrong, NotEnoughData, IllFormedName, IllFormedAttrTypeValue, IllFormedInfoBlock, @@ -15,7 +17,7 @@ pub enum X509ParseError { IllFormedAlgoInfo, IllFormedKey, IllFormedEverything, IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound, UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData, - InvalidSignatureHash, + InvalidSignatureHash, InvalidECDSAKey, KeyNotFound, SignatureNotFound, SignatureVerificationFailed } @@ -26,6 +28,12 @@ impl From for X509ParseError { } } +impl From for X509ParseError { + fn from(e: ASN1EncodeErr) -> X509ParseError { + X509ParseError::ASN1EncodeError(e) + } +} + impl From for X509ParseError { fn from(e: RSAError) -> X509ParseError { X509ParseError::RSAError(e) @@ -38,6 +46,12 @@ impl From for X509ParseError { } } +impl From for X509ParseError { + fn from(e: ECDSAError) -> X509ParseError { + X509ParseError::ECDSAError(e) + } +} + impl From for X509ParseError { fn from(e: DSADecodeError) -> X509ParseError { X509ParseError::DSASigParseError(e) diff --git a/src/lib.rs b/src/lib.rs index 2a2dde1..cd96f66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,6 +103,7 @@ fn decode_certificate(x: &ASN1Block) pub fn parse_x509(buffer: &[u8]) -> Result { let blocks = from_der(&buffer[..])?; + println!("blocks: {:?}", blocks); match blocks.first() { None => Err(X509ParseError::NotEnoughData), @@ -184,27 +185,27 @@ mod tests { parse_x509(&buffer) } - #[test] - fn rsa_tests() { - assert!(can_parse("test/rsa2048-1.der").is_ok()); - assert!(can_parse("test/rsa2048-2.der").is_ok()); - assert!(can_parse("test/rsa4096-1.der").is_ok()); - assert!(can_parse("test/rsa4096-2.der").is_ok()); - assert!(can_parse("test/rsa4096-3.der").is_ok()); - } - - #[test] - fn dsa_tests() { - assert!(can_parse("test/dsa2048-1.der").is_ok()); - assert!(can_parse("test/dsa2048-2.der").is_ok()); - assert!(can_parse("test/dsa3072-1.der").is_ok()); - assert!(can_parse("test/dsa3072-2.der").is_ok()); - } +// #[test] +// fn rsa_tests() { +// assert!(can_parse("test/rsa2048-1.der").is_ok()); +// assert!(can_parse("test/rsa2048-2.der").is_ok()); +// assert!(can_parse("test/rsa4096-1.der").is_ok()); +// assert!(can_parse("test/rsa4096-2.der").is_ok()); +// assert!(can_parse("test/rsa4096-3.der").is_ok()); +// } // // #[test] -// fn ecc_tests() { -// assert!(can_parse("test/ec384-1.der").is_ok()); -// assert!(can_parse("test/ec384-2.der").is_ok()); -// assert!(can_parse("test/ec384-3.der").is_ok()); +// fn dsa_tests() { +// assert!(can_parse("test/dsa2048-1.der").is_ok()); +// assert!(can_parse("test/dsa2048-2.der").is_ok()); +// assert!(can_parse("test/dsa3072-1.der").is_ok()); +// assert!(can_parse("test/dsa3072-2.der").is_ok()); // } + + #[test] + fn ecc_tests() { + assert!(can_parse("test/ec384-1.der").is_ok()); + assert!(can_parse("test/ec384-2.der").is_ok()); + assert!(can_parse("test/ec384-3.der").is_ok()); + } } diff --git a/src/publickey.rs b/src/publickey.rs index ae78962..b4c97d7 100644 --- a/src/publickey.rs +++ b/src/publickey.rs @@ -3,12 +3,14 @@ use num::{BigInt,BigUint}; use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1, der_decode,der_encode,from_der}; use simple_dsa::dsa::{DSAParameters,DSAPublicKey}; +use simple_dsa::ecdsa::{EllipticCurve,ECCPublicKey}; use simple_rsa::RSAPublicKey; #[derive(Clone,Debug,PartialEq)] pub enum X509PublicKey { DSA(DSAPublicKey), RSA(RSAPublicKey), + ECDSA(ECCPublicKey) } impl FromASN1 for X509PublicKey { @@ -29,10 +31,10 @@ impl FromASN1 for X509PublicKey { } impl ToASN1 for X509PublicKey { - type Error = ASN1EncodeErr; + type Error = X509ParseError; fn to_asn1_class(&self, c: ASN1Class) - -> Result,ASN1EncodeErr> + -> Result,X509ParseError> { let block = encode_public_key(c, self)?; Ok(vec![block]) @@ -59,16 +61,22 @@ fn decode_public_key(block: &ASN1Block) let key = decode_dsa_key(&info[1], ¶ms)?; return Ok(X509PublicKey::DSA(key)); } else { - println!("Bad malginfo: {:?}", malginfo); - println!("info[0]: {:?}", info[0]); return Err(X509ParseError::IllFormedKey) } } - println!("Bad OID: {:?}", id); + if id == oid!(1,2,840,10045,2,1) { + if let Some(alginfo) = malginfo { + println!("alginfo: {:?}", alginfo); + let curve = decode_ecc_info(&alginfo)?; + let key = decode_ecc_key(&info[1], &curve)?; + return Ok(X509PublicKey::ECDSA(key)); + } else { + return Err(X509ParseError::IllFormedKey) + } + } Err(X509ParseError::IllFormedKey) } _ => { - println!("Bad block: {:?}", block); Err(X509ParseError::IllFormedKey) } } @@ -90,16 +98,17 @@ fn strip_algident(block: &ASN1Block) } fn encode_public_key(c: ASN1Class, key: &X509PublicKey) - -> Result + -> Result { match key { - &X509PublicKey::RSA(ref rsa) => encode_rsa_pubkey(c, rsa), - &X509PublicKey::DSA(ref dsa) => encode_dsa_pubkey(c, dsa) + &X509PublicKey::RSA(ref rsa) => encode_rsa_pubkey(c, rsa), + &X509PublicKey::DSA(ref dsa) => encode_dsa_pubkey(c, dsa), + &X509PublicKey::ECDSA(ref ecc) => encode_ecc_pubkey(c, ecc) } } fn encode_rsa_pubkey(c: ASN1Class, key: &RSAPublicKey) - -> Result + -> Result { let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,113549,1,1,1)); let objkey = encode_rsa_key(c, key)?; @@ -107,7 +116,7 @@ fn encode_rsa_pubkey(c: ASN1Class, key: &RSAPublicKey) } fn encode_dsa_pubkey(c: ASN1Class, key: &DSAPublicKey) - -> Result + -> Result { let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10040,4,1)); let objparams = encode_dsa_info(c, &key.params); @@ -116,8 +125,18 @@ fn encode_dsa_pubkey(c: ASN1Class, key: &DSAPublicKey) Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey])) } +fn encode_ecc_pubkey(c: ASN1Class, key: &ECCPublicKey) + -> Result +{ + let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,4,1)); + let objparams = encode_ecc_info(c, &key.curve)?; + let objkey = encode_ecc_key(c, key)?; + let headinfo = ASN1Block::Sequence(c, 0, vec![objoid, objparams]); + Ok(ASN1Block::Sequence(c, 0, vec![headinfo, objkey])) +} + fn encode_rsa_key(c: ASN1Class, k: &RSAPublicKey) - -> Result + -> Result { let bstr = der_encode(k)?; Ok(ASN1Block::BitString(c, 0, bstr.len() * 8, bstr)) @@ -134,7 +153,7 @@ fn decode_rsa_key(b: &ASN1Block) -> Result { } fn encode_dsa_key(c: ASN1Class, k: &DSAPublicKey) - -> Result + -> Result { let bstr = der_encode(k)?; Ok(ASN1Block::BitString(c, 0, bstr.len() * 8, bstr)) @@ -161,7 +180,28 @@ fn decode_dsa_key(b: &ASN1Block, params: &DSAParameters) } } _ => - Err(X509ParseError::InvalidRSAKey) + Err(X509ParseError::InvalidDSAKey) + } +} + +fn encode_ecc_key(c: ASN1Class, k: &ECCPublicKey) + -> Result +{ + unimplemented!() +} + +fn decode_ecc_key(b: &ASN1Block, curve: &EllipticCurve) + -> Result +{ + match b { + &ASN1Block::BitString(_, _, size, ref vec) if size % 8 == 0 => { + println!("vec[{}/{}]: {:?}", size, vec.len(), vec); + let vals = from_der(&vec); + println!("vals: {:?}", vals); + unimplemented!() + } + _ => + Err(X509ParseError::InvalidECDSAKey) } } @@ -187,6 +227,26 @@ fn encode_dsa_info(c: ASN1Class, params: &DSAParameters) -> ASN1Block { ASN1Block::Sequence(c, 0, vec![p, q, g]) } +fn decode_ecc_info(v: &ASN1Block) + -> Result +{ + let bs = vec![v.clone()]; + EllipticCurve::from_asn1(bs.as_slice()).map_err(X509ParseError::from) + .map(|(x,_)| x) +} + +fn encode_ecc_info(c: ASN1Class, curve: &EllipticCurve) + -> Result +{ + let res = curve.to_asn1_class(c)?; + match res.first() { + None => + Err(X509ParseError::UnknownAlgorithm), + Some(x) => + Ok(x.clone()) + } +} + fn decode_biguint(b: &ASN1Block) -> Result { match b { &ASN1Block::Integer(_, _, ref v) => { @@ -240,4 +300,21 @@ mod test { assert_eq!(x509public, x509public2); } } + + fn ecc_info_test(curve: &EllipticCurve) { + let x = encode_ecc_info(ASN1Class::Universal, curve).unwrap(); + let curve2 = decode_ecc_info(&x).unwrap(); + assert_eq!(curve, &curve2); + } + + #[test] + fn ecdsa_public_key_tests() { + ecc_info_test(&EllipticCurve::p192()); + ecc_info_test(&EllipticCurve::p224()); + ecc_info_test(&EllipticCurve::p256()); + ecc_info_test(&EllipticCurve::p384()); + ecc_info_test(&EllipticCurve::p521()); + for _ in 0..NUM_TESTS { + } + } }