Now supports ECDSA signatures.
This commit is contained in:
@@ -6,7 +6,7 @@ use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1};
|
|||||||
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
pub enum HashAlgorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
|
||||||
|
|
||||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
pub enum PublicKeyInfo { RSA, DSA, EC }
|
pub enum PublicKeyInfo { RSA, DSA, ECDSA }
|
||||||
|
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
pub struct AlgorithmIdentifier {
|
pub struct AlgorithmIdentifier {
|
||||||
@@ -80,31 +80,31 @@ pub fn decode_algorithm_ident(x: &ASN1Block)
|
|||||||
if oid == oid!(1,2,840,10045,4,1) {
|
if oid == oid!(1,2,840,10045,4,1) {
|
||||||
return Ok(AlgorithmIdentifier {
|
return Ok(AlgorithmIdentifier {
|
||||||
hash: HashAlgorithm::SHA1,
|
hash: HashAlgorithm::SHA1,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if oid == oid!(1,2,840,10045,4,3,1) {
|
if oid == oid!(1,2,840,10045,4,3,1) {
|
||||||
return Ok(AlgorithmIdentifier {
|
return Ok(AlgorithmIdentifier {
|
||||||
hash: HashAlgorithm::SHA224,
|
hash: HashAlgorithm::SHA224,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if oid == oid!(1,2,840,10045,4,3,2) {
|
if oid == oid!(1,2,840,10045,4,3,2) {
|
||||||
return Ok(AlgorithmIdentifier {
|
return Ok(AlgorithmIdentifier {
|
||||||
hash: HashAlgorithm::SHA256,
|
hash: HashAlgorithm::SHA256,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if oid == oid!(1,2,840,10045,4,3,3) {
|
if oid == oid!(1,2,840,10045,4,3,3) {
|
||||||
return Ok(AlgorithmIdentifier {
|
return Ok(AlgorithmIdentifier {
|
||||||
hash: HashAlgorithm::SHA384,
|
hash: HashAlgorithm::SHA384,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if oid == oid!(1,2,840,10045,4,3,4) {
|
if oid == oid!(1,2,840,10045,4,3,4) {
|
||||||
return Ok(AlgorithmIdentifier {
|
return Ok(AlgorithmIdentifier {
|
||||||
hash: HashAlgorithm::SHA512,
|
hash: HashAlgorithm::SHA512,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
|
// if oid == oid!(2,16,840,1,101,3,4,2,1) {
|
||||||
@@ -232,7 +232,7 @@ fn encode_algorithm_ident(c: ASN1Class, x: &AlgorithmIdentifier)
|
|||||||
Err(SigAlgEncodeError::InvalidHash),
|
Err(SigAlgEncodeError::InvalidHash),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PublicKeyInfo::EC => {
|
PublicKeyInfo::ECDSA=> {
|
||||||
match x.hash {
|
match x.hash {
|
||||||
HashAlgorithm::SHA1 => {
|
HashAlgorithm::SHA1 => {
|
||||||
let o = oid!(1,2,840,10045,4,1);
|
let o = oid!(1,2,840,10045,4,1);
|
||||||
@@ -320,31 +320,31 @@ mod test {
|
|||||||
const EC1: AlgorithmIdentifier =
|
const EC1: AlgorithmIdentifier =
|
||||||
AlgorithmIdentifier{
|
AlgorithmIdentifier{
|
||||||
hash: HashAlgorithm::SHA1,
|
hash: HashAlgorithm::SHA1,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
};
|
};
|
||||||
|
|
||||||
const EC224: AlgorithmIdentifier =
|
const EC224: AlgorithmIdentifier =
|
||||||
AlgorithmIdentifier{
|
AlgorithmIdentifier{
|
||||||
hash: HashAlgorithm::SHA224,
|
hash: HashAlgorithm::SHA224,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
};
|
};
|
||||||
|
|
||||||
const EC256: AlgorithmIdentifier =
|
const EC256: AlgorithmIdentifier =
|
||||||
AlgorithmIdentifier{
|
AlgorithmIdentifier{
|
||||||
hash: HashAlgorithm::SHA256,
|
hash: HashAlgorithm::SHA256,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
};
|
};
|
||||||
|
|
||||||
const EC384: AlgorithmIdentifier =
|
const EC384: AlgorithmIdentifier =
|
||||||
AlgorithmIdentifier{
|
AlgorithmIdentifier{
|
||||||
hash: HashAlgorithm::SHA384,
|
hash: HashAlgorithm::SHA384,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
};
|
};
|
||||||
|
|
||||||
const EC512: AlgorithmIdentifier =
|
const EC512: AlgorithmIdentifier =
|
||||||
AlgorithmIdentifier{
|
AlgorithmIdentifier{
|
||||||
hash: HashAlgorithm::SHA512,
|
hash: HashAlgorithm::SHA512,
|
||||||
algo: PublicKeyInfo::EC
|
algo: PublicKeyInfo::ECDSA
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Arbitrary for AlgorithmIdentifier {
|
impl Arbitrary for AlgorithmIdentifier {
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ pub enum X509ParseError {
|
|||||||
IllFormedAlgoInfo, IllFormedKey, IllFormedEverything,
|
IllFormedAlgoInfo, IllFormedKey, IllFormedEverything,
|
||||||
IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound,
|
IllegalStringValue, NoSerialNumber, InvalidDSAInfo, ItemNotFound,
|
||||||
UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData,
|
UnknownAlgorithm, InvalidRSAKey, InvalidDSAKey, InvalidSignatureData,
|
||||||
InvalidSignatureHash, InvalidECDSAKey,
|
InvalidSignatureHash, InvalidECDSAKey, InvalidPointForm,
|
||||||
|
CompressedPointUnsupported,
|
||||||
KeyNotFound,
|
KeyNotFound,
|
||||||
SignatureNotFound, SignatureVerificationFailed
|
SignatureNotFound, SignatureVerificationFailed
|
||||||
}
|
}
|
||||||
|
|||||||
57
src/lib.rs
57
src/lib.rs
@@ -26,7 +26,7 @@ use error::X509ParseError;
|
|||||||
use misc::{X509Serial,X509Version,decode_signature};
|
use misc::{X509Serial,X509Version,decode_signature};
|
||||||
use publickey::X509PublicKey;
|
use publickey::X509PublicKey;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use sha2::{Sha224,Sha256};
|
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||||
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
use simple_asn1::{ASN1Block,FromASN1,der_decode,from_der};
|
||||||
use simple_rsa::{SIGNING_HASH_SHA1, SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
use simple_rsa::{SIGNING_HASH_SHA1, SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
||||||
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
||||||
@@ -103,7 +103,6 @@ fn decode_certificate(x: &ASN1Block)
|
|||||||
|
|
||||||
pub fn parse_x509(buffer: &[u8]) -> Result<Certificate,X509ParseError> {
|
pub fn parse_x509(buffer: &[u8]) -> Result<Certificate,X509ParseError> {
|
||||||
let blocks = from_der(&buffer[..])?;
|
let blocks = from_der(&buffer[..])?;
|
||||||
println!("blocks: {:?}", blocks);
|
|
||||||
match blocks.first() {
|
match blocks.first() {
|
||||||
None =>
|
None =>
|
||||||
Err(X509ParseError::NotEnoughData),
|
Err(X509ParseError::NotEnoughData),
|
||||||
@@ -160,6 +159,28 @@ fn check_signature(alg: &AlgorithmIdentifier,
|
|||||||
Err(X509ParseError::InvalidSignatureHash)
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(PublicKeyInfo::ECDSA, &X509PublicKey::ECDSA(ref key)) => {
|
||||||
|
let ecdsa_sig = der_decode(&sig)?;
|
||||||
|
match alg.hash {
|
||||||
|
HashAlgorithm::SHA1
|
||||||
|
if key.verify::<Sha1>(block, &ecdsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
HashAlgorithm::SHA224
|
||||||
|
if key.verify::<Sha224>(block, &ecdsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
HashAlgorithm::SHA256
|
||||||
|
if key.verify::<Sha256>(block, &ecdsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
HashAlgorithm::SHA384
|
||||||
|
if key.verify::<Sha384>(block, &ecdsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
HashAlgorithm::SHA512
|
||||||
|
if key.verify::<Sha512>(block, &ecdsa_sig) =>
|
||||||
|
Ok(()),
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidSignatureHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidSignatureData)
|
Err(X509ParseError::InvalidSignatureData)
|
||||||
}
|
}
|
||||||
@@ -185,22 +206,22 @@ mod tests {
|
|||||||
parse_x509(&buffer)
|
parse_x509(&buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn rsa_tests() {
|
fn rsa_tests() {
|
||||||
// assert!(can_parse("test/rsa2048-1.der").is_ok());
|
assert!(can_parse("test/rsa2048-1.der").is_ok());
|
||||||
// assert!(can_parse("test/rsa2048-2.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-1.der").is_ok());
|
||||||
// assert!(can_parse("test/rsa4096-2.der").is_ok());
|
assert!(can_parse("test/rsa4096-2.der").is_ok());
|
||||||
// assert!(can_parse("test/rsa4096-3.der").is_ok());
|
assert!(can_parse("test/rsa4096-3.der").is_ok());
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn dsa_tests() {
|
fn dsa_tests() {
|
||||||
// assert!(can_parse("test/dsa2048-1.der").is_ok());
|
assert!(can_parse("test/dsa2048-1.der").is_ok());
|
||||||
// assert!(can_parse("test/dsa2048-2.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-1.der").is_ok());
|
||||||
// assert!(can_parse("test/dsa3072-2.der").is_ok());
|
assert!(can_parse("test/dsa3072-2.der").is_ok());
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ecc_tests() {
|
fn ecc_tests() {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use error::X509ParseError;
|
use error::X509ParseError;
|
||||||
use num::{BigInt,BigUint};
|
use num::{BigInt,BigUint};
|
||||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1EncodeErr,FromASN1,OID,ToASN1,
|
use num::bigint::Sign;
|
||||||
|
use simple_asn1::{ASN1Block,ASN1Class,FromASN1,OID,ToASN1,
|
||||||
der_decode,der_encode,from_der};
|
der_decode,der_encode,from_der};
|
||||||
use simple_dsa::dsa::{DSAParameters,DSAPublicKey};
|
use simple_dsa::dsa::{DSAParameters,DSAPublicKey};
|
||||||
use simple_dsa::ecdsa::{EllipticCurve,ECCPublicKey};
|
use simple_dsa::ecdsa::{EllipticCurve,ECCPoint,ECCPublicKey};
|
||||||
use simple_rsa::RSAPublicKey;
|
use simple_rsa::RSAPublicKey;
|
||||||
|
|
||||||
#[derive(Clone,Debug,PartialEq)]
|
#[derive(Clone,Debug,PartialEq)]
|
||||||
@@ -66,7 +67,6 @@ fn decode_public_key(block: &ASN1Block)
|
|||||||
}
|
}
|
||||||
if id == oid!(1,2,840,10045,2,1) {
|
if id == oid!(1,2,840,10045,2,1) {
|
||||||
if let Some(alginfo) = malginfo {
|
if let Some(alginfo) = malginfo {
|
||||||
println!("alginfo: {:?}", alginfo);
|
|
||||||
let curve = decode_ecc_info(&alginfo)?;
|
let curve = decode_ecc_info(&alginfo)?;
|
||||||
let key = decode_ecc_key(&info[1], &curve)?;
|
let key = decode_ecc_key(&info[1], &curve)?;
|
||||||
return Ok(X509PublicKey::ECDSA(key));
|
return Ok(X509PublicKey::ECDSA(key));
|
||||||
@@ -128,7 +128,7 @@ fn encode_dsa_pubkey(c: ASN1Class, key: &DSAPublicKey)
|
|||||||
fn encode_ecc_pubkey(c: ASN1Class, key: &ECCPublicKey)
|
fn encode_ecc_pubkey(c: ASN1Class, key: &ECCPublicKey)
|
||||||
-> Result<ASN1Block, X509ParseError>
|
-> Result<ASN1Block, X509ParseError>
|
||||||
{
|
{
|
||||||
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,4,1));
|
let objoid = ASN1Block::ObjectIdentifier(c, 0, oid!(1,2,840,10045,2,1));
|
||||||
let objparams = encode_ecc_info(c, &key.curve)?;
|
let objparams = encode_ecc_info(c, &key.curve)?;
|
||||||
let objkey = encode_ecc_key(c, key)?;
|
let objkey = encode_ecc_key(c, key)?;
|
||||||
let headinfo = ASN1Block::Sequence(c, 0, vec![objoid, objparams]);
|
let headinfo = ASN1Block::Sequence(c, 0, vec![objoid, objparams]);
|
||||||
@@ -187,7 +187,26 @@ fn decode_dsa_key(b: &ASN1Block, params: &DSAParameters)
|
|||||||
fn encode_ecc_key(c: ASN1Class, k: &ECCPublicKey)
|
fn encode_ecc_key(c: ASN1Class, k: &ECCPublicKey)
|
||||||
-> Result<ASN1Block, X509ParseError>
|
-> Result<ASN1Block, X509ParseError>
|
||||||
{
|
{
|
||||||
unimplemented!()
|
let mut bytes = vec![4];
|
||||||
|
let (xsign, mut xbytes) = k.Q.x.to_bytes_be();
|
||||||
|
let (ysign, mut ybytes) = k.Q.y.to_bytes_be();
|
||||||
|
let goalsize = (k.curve.n.bits() + 7) / 8;
|
||||||
|
|
||||||
|
if (xsign != Sign::Plus) || (ysign != Sign::Plus) {
|
||||||
|
return Err(X509ParseError::InvalidPointForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
while xbytes.len() < goalsize {
|
||||||
|
xbytes.insert(0,0);
|
||||||
|
}
|
||||||
|
while ybytes.len() < goalsize {
|
||||||
|
ybytes.insert(0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes.append(&mut xbytes);
|
||||||
|
bytes.append(&mut ybytes);
|
||||||
|
|
||||||
|
Ok(ASN1Block::BitString(c, 0, (goalsize + 1) * 8, bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_ecc_key(b: &ASN1Block, curve: &EllipticCurve)
|
fn decode_ecc_key(b: &ASN1Block, curve: &EllipticCurve)
|
||||||
@@ -195,10 +214,22 @@ fn decode_ecc_key(b: &ASN1Block, curve: &EllipticCurve)
|
|||||||
{
|
{
|
||||||
match b {
|
match b {
|
||||||
&ASN1Block::BitString(_, _, size, ref vec) if size % 8 == 0 => {
|
&ASN1Block::BitString(_, _, size, ref vec) if size % 8 == 0 => {
|
||||||
println!("vec[{}/{}]: {:?}", size, vec.len(), vec);
|
match vec.split_first() {
|
||||||
let vals = from_der(&vec);
|
Some((&2, _)) =>
|
||||||
println!("vals: {:?}", vals);
|
Err(X509ParseError::CompressedPointUnsupported),
|
||||||
unimplemented!()
|
Some((&3, _)) =>
|
||||||
|
Err(X509ParseError::CompressedPointUnsupported),
|
||||||
|
Some((&4, input)) => {
|
||||||
|
let bytesize = (curve.n.bits() + 7) / 8;
|
||||||
|
let (xbytes, ybytes) = input.split_at(bytesize);
|
||||||
|
let x = BigInt::from_bytes_be(Sign::Plus, xbytes);
|
||||||
|
let y = BigInt::from_bytes_be(Sign::Plus, ybytes);
|
||||||
|
let point = ECCPoint::new(curve, x, y)?;
|
||||||
|
Ok(ECCPublicKey::new(curve, &point))
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
Err(X509ParseError::InvalidPointForm)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ =>
|
_ =>
|
||||||
Err(X509ParseError::InvalidECDSAKey)
|
Err(X509ParseError::InvalidECDSAKey)
|
||||||
@@ -265,6 +296,7 @@ fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use simple_dsa::dsa::{DSAParameterSize,DSAKeyPair};
|
use simple_dsa::dsa::{DSAParameterSize,DSAKeyPair};
|
||||||
|
use simple_dsa::ecdsa::{ECCKeyPair};
|
||||||
use simple_rsa::RSAKeyPair;
|
use simple_rsa::RSAKeyPair;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -309,12 +341,22 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ecdsa_public_key_tests() {
|
fn ecdsa_public_key_tests() {
|
||||||
|
let curve256 = EllipticCurve::p256();
|
||||||
ecc_info_test(&EllipticCurve::p192());
|
ecc_info_test(&EllipticCurve::p192());
|
||||||
ecc_info_test(&EllipticCurve::p224());
|
ecc_info_test(&EllipticCurve::p224());
|
||||||
ecc_info_test(&EllipticCurve::p256());
|
ecc_info_test(&curve256);
|
||||||
ecc_info_test(&EllipticCurve::p384());
|
ecc_info_test(&EllipticCurve::p384());
|
||||||
ecc_info_test(&EllipticCurve::p521());
|
ecc_info_test(&EllipticCurve::p521());
|
||||||
for _ in 0..NUM_TESTS {
|
for _ in 0..NUM_TESTS {
|
||||||
|
let pair = ECCKeyPair::generate(&curve256);
|
||||||
|
let public = pair.public;
|
||||||
|
let block = encode_ecc_key(ASN1Class::Universal, &public).unwrap();
|
||||||
|
let public2 = decode_ecc_key(&block, &curve256).unwrap();
|
||||||
|
assert_eq!(public, public2);
|
||||||
|
let x509public = X509PublicKey::ECDSA(public);
|
||||||
|
let block2 = encode_public_key(ASN1Class::Universal, &x509public).unwrap();
|
||||||
|
let x509public2 = decode_public_key(&block2).unwrap();
|
||||||
|
assert_eq!(x509public, x509public2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user