Parse the subject public key block, and add some crypto that probably needs to be moved elsewhere.

This commit is contained in:
2017-12-21 20:31:26 -08:00
parent 97990f2ebe
commit 826a5dd082

View File

@@ -9,10 +9,10 @@ extern crate simple_asn1;
use chrono::{DateTime,Utc};
use num::{BigInt,BigUint,ToPrimitive};
use simple_asn1::{ASN1Block,ASN1Class,FromASN1,OID,ToASN1};
use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr};
use simple_asn1::{ASN1DecodeErr,ASN1EncodeErr,der_decode};
#[derive(Clone,Debug,PartialEq)]
enum HashAlgorithm { MD2, MD5, SHA1, SHA224, SHA256, SHA384, SHA512 }
enum HashAlgorithm { None, MD2, MD5, SHA1, SHA224, SHA256, SHA384, SHA512 }
#[derive(Clone,Debug,PartialEq)]
enum PubKeyAlgorithm { RSA, RSAPSS, DSA, EC, DH, Unknown(OID) }
@@ -23,7 +23,52 @@ enum X509ParseError {
NotEnoughData, ItemNotFound, IllegalFormat, NoSerialNumber,
NoSignatureAlgorithm, NoNameInformation, IllFormedNameInformation,
NoValueForName, UnknownAttrTypeValue, IllegalStringValue, NoValidityInfo,
ImproperValidityInfo
ImproperValidityInfo, NoSubjectPublicKeyInfo, ImproperSubjectPublicKeyInfo,
BadPublicKeyAlgorithm, UnsupportedPublicKey, InvalidRSAKey,
UnsupportedExtension, UnexpectedNegativeNumber, MissingNumber
}
#[derive(Clone,Debug,PartialEq)]
enum X509PublicKey {
RSA(RSAPublicKey)
}
#[derive(Clone,Debug,PartialEq)]
struct RSAPublicKey {
bit_size: usize,
n: BigUint,
e: BigUint
}
impl FromASN1 for RSAPublicKey {
type Error = X509ParseError;
fn from_asn1(bs: &[ASN1Block])
-> Result<(RSAPublicKey,&[ASN1Block]),X509ParseError>
{
match bs.split_first() {
None =>
Err(X509ParseError::ItemNotFound),
Some((&ASN1Block::Sequence(_, ref items), rest))
if items.len() == 2 =>
{
let n = decode_biguint(&items[0])?;
let e = decode_biguint(&items[1])?;
let nsize = n.bits();
let mut rsa_size = 256;
while rsa_size < nsize {
rsa_size = rsa_size * 2;
}
let res = RSAPublicKey{ bit_size: rsa_size, n: n, e: e };
Ok((res, rest))
}
Some(_) =>
Err(X509ParseError::InvalidRSAKey)
}
}
}
impl From<ASN1DecodeErr> for X509ParseError {
@@ -108,6 +153,12 @@ impl FromASN1 for SignatureAlgorithm {
Some((x, rest)) => {
match x {
&ASN1Block::ObjectIdentifier(_, ref oid) => {
if oid == oid!(1,2,840,113549,1,1,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::RSA
}, rest));
}
if oid == oid!(1,2,840,113549,1,1,5) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
@@ -150,12 +201,24 @@ impl FromASN1 for SignatureAlgorithm {
key_alg: PubKeyAlgorithm::RSA
}, rest));
}
if oid == oid!(1,2,840,10040,4,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::DSA
}, rest));
}
if oid == oid!(1,2,840,10040,4,3) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
key_alg: PubKeyAlgorithm::DSA
}, rest));
}
if oid == oid!(1,2,840,10045,2,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::EC
}, rest));
}
if oid == oid!(1,2,840,10045,4,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
@@ -186,6 +249,12 @@ impl FromASN1 for SignatureAlgorithm {
key_alg: PubKeyAlgorithm::EC
}, rest));
}
if oid == oid!(1,2,840,113549,1,1,10) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::RSAPSS
}, rest));
}
if oid == oid!(2,16,840,1,101,3,4,2,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA256,
@@ -222,6 +291,12 @@ impl FromASN1 for SignatureAlgorithm {
key_alg: PubKeyAlgorithm::DSA
}, rest));
}
if oid == oid!(1,2,840,10046,2,1) {
return Ok((SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::DH
}, rest));
}
Err(X509ParseError::ItemNotFound)
}
_ =>
@@ -253,6 +328,7 @@ impl ToASN1 for SignatureAlgorithm {
let oid = match self.key_alg {
PubKeyAlgorithm::RSA =>
match self.hash_alg {
HashAlgorithm::None => oid!(1,2,840,113549,1,1,1),
HashAlgorithm::MD2 => oid!(1,2,840,113549,1,1,2),
HashAlgorithm::MD5 => oid!(1,2,840,113549,1,1,4),
HashAlgorithm::SHA1 => oid!(1,2,840,113549,1,1,5),
@@ -263,6 +339,7 @@ impl ToASN1 for SignatureAlgorithm {
},
PubKeyAlgorithm::RSAPSS =>
match self.hash_alg {
HashAlgorithm::None => oid!(1,2,840,113549,1,1,10),
HashAlgorithm::MD2 => return Err(badval),
HashAlgorithm::MD5 => return Err(badval),
HashAlgorithm::SHA1 => return Err(badval),
@@ -273,6 +350,7 @@ impl ToASN1 for SignatureAlgorithm {
},
PubKeyAlgorithm::DSA =>
match self.hash_alg {
HashAlgorithm::None => oid!(1,2,840,10040,4,1),
HashAlgorithm::MD2 => return Err(badval),
HashAlgorithm::MD5 => return Err(badval),
HashAlgorithm::SHA1 => oid!(1,2,840,10040,4,3),
@@ -283,6 +361,7 @@ impl ToASN1 for SignatureAlgorithm {
},
PubKeyAlgorithm::EC =>
match self.hash_alg {
HashAlgorithm::None => oid!(1,2,840,10045,2,1),
HashAlgorithm::MD2 => return Err(badval),
HashAlgorithm::MD5 => return Err(badval),
HashAlgorithm::SHA1 => oid!(1,2,840,10045,4,1),
@@ -292,23 +371,29 @@ impl ToASN1 for SignatureAlgorithm {
HashAlgorithm::SHA512 => oid!(1,2,840,10045,4,3,4),
},
PubKeyAlgorithm::DH =>
return Err(badval),
PubKeyAlgorithm::Unknown(_) =>
return Err(badval)
match self.hash_alg {
HashAlgorithm::None => oid!(1,2,840,10046,2,1),
_ => return Err(badval)
}
PubKeyAlgorithm::Unknown(ref oid) =>
match self.hash_alg {
HashAlgorithm::None => oid.clone(),
_ => return Err(badval)
}
};
Ok(vec![ASN1Block::ObjectIdentifier(c, oid)])
}
}
#[derive(Clone,Debug,PartialEq)]
struct Certificate {
version: u32,
serial: BigInt,
sig_alg: SignatureAlgorithm,
issuer_dn: String,
subject_dn: String,
valid_start: (),
valid_end: (),
public_key: (),
serial: BigUint,
signature_alg: SignatureAlgorithm,
issuer: InfoBlock,
subject: InfoBlock,
validity: Validity,
subject_key: X509PublicKey,
extensions: Vec<()>
}
@@ -344,7 +429,7 @@ impl FromASN1 for Certificate {
}
fn get_tbs_certificate(x: &ASN1Block)
-> Result<(),X509ParseError>
-> Result<Certificate,X509ParseError>
{
match x {
&ASN1Block::Sequence(_, ref v0) => {
@@ -352,7 +437,7 @@ fn get_tbs_certificate(x: &ASN1Block)
// version [0] Version DEFAULT v1,
let (version, v1) = get_version(v0)?;
// serialNumber CertificateSerialNumber,
let (serial, v2) = get_serial_number(v1)?;
let (serial, v2) = get_serial(v1)?;
// signature AlgorithmIdentifier,
let (algo, v3) = get_signature_info(v2)?;
// issuer Name,
@@ -361,8 +446,16 @@ fn get_tbs_certificate(x: &ASN1Block)
let (validity, v5) = get_validity_data(v4)?;
// subject Name,
let (subject, v6) = get_name_data(v5)?;
println!("v6: {:?}", v6);
// subjectPublicKeyInfo SubjectPublicKeyInfo,
let (subpki, v7) = get_subject_pki(v6)?;
if (version < 3) && !v7.is_empty() {
return Err(X509ParseError::UnsupportedExtension)
}
// FIXME: Support v3 extensions
if !v7.is_empty() {
return Err(X509ParseError::UnsupportedExtension)
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
// -- If present, version MUST be v2 or v3
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
@@ -370,12 +463,18 @@ fn get_tbs_certificate(x: &ASN1Block)
// extensions [3] Extensions OPTIONAL
// -- If present, version MUST be v3 -- }
//
println!("version: {}", version);
println!("serial#: {}", serial);
println!("issuer: {:?}", issuer);
println!("validity: {:?}", validity);
println!("subject: {:?}", subject);
Err(X509ParseError::IllegalFormat)
}
Ok(Certificate{
version: version,
serial: serial,
signature_alg: algo,
issuer: issuer,
subject: subject,
validity: validity,
subject_key: subpki,
extensions: vec![]
})
}
_ =>
Err(X509ParseError::IllegalFormat)
@@ -415,18 +514,29 @@ fn get_version(bs: &[ASN1Block])
}
}
fn get_serial_number(bs: &[ASN1Block])
fn get_serial(bs: &[ASN1Block])
-> Result<(BigUint,&[ASN1Block]),X509ParseError>
{
match bs.split_first() {
Some((&ASN1Block::Integer(_, ref v), rest)) => {
Some((first, rest)) => {
let res = decode_biguint(first)?;
Ok((res, rest))
}
None =>
Err(X509ParseError::NoSerialNumber)
}
}
fn decode_biguint(b: &ASN1Block) -> Result<BigUint,X509ParseError> {
match b {
&ASN1Block::Integer(_, ref v) => {
match v.to_biguint() {
Some(sn) => Ok((sn, rest)),
_ => Err(X509ParseError::NoSerialNumber)
Some(sn) => Ok(sn),
_ => Err(X509ParseError::UnexpectedNegativeNumber)
}
}
_ =>
Err(X509ParseError::NoSerialNumber)
Err(X509ParseError::MissingNumber)
}
}
@@ -743,6 +853,52 @@ fn get_time(b: &ASN1Block) -> Result<DateTime<Utc>, X509ParseError> {
}
}
fn get_subject_pki(b: &[ASN1Block])
-> Result<(X509PublicKey, &[ASN1Block]), X509ParseError>
{
match b.split_first() {
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING }
Some((&ASN1Block::Sequence(_, ref info), rest)) => {
if info.len() != 2 {
return Err(X509ParseError::ImproperSubjectPublicKeyInfo)
}
let alginfo = get_signature_alg(&info[0])?;
// this better not really be a signature with a hash
if alginfo.hash_alg != HashAlgorithm::None {
return Err(X509ParseError::BadPublicKeyAlgorithm)
}
// the actual key format depends on the algorithm
match alginfo.key_alg {
PubKeyAlgorithm::RSA => {
let key = get_rsa_public_key(&info[1])?;
Ok((X509PublicKey::RSA(key), rest))
}
_ => {
Err(X509ParseError::UnsupportedPublicKey)
}
}
}
_ =>
Err(X509ParseError::NoSubjectPublicKeyInfo)
}
}
fn get_rsa_public_key(b: &ASN1Block)
-> Result<RSAPublicKey, X509ParseError>
{
match b {
&ASN1Block::BitString(_, size, ref vec) if size % 8 == 0 => {
der_decode(vec)
}
_ =>
Err(X509ParseError::InvalidRSAKey)
}
}
#[cfg(test)]
mod tests {
use quickcheck::{Arbitrary,Gen};
@@ -794,6 +950,10 @@ mod tests {
impl Arbitrary for SignatureAlgorithm {
fn arbitrary<G: Gen>(g: &mut G) -> SignatureAlgorithm {
let possibles = vec![
SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::RSA
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
key_alg: PubKeyAlgorithm::RSA
@@ -822,10 +982,18 @@ mod tests {
hash_alg: HashAlgorithm::SHA224,
key_alg: PubKeyAlgorithm::RSA
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::DSA
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
key_alg: PubKeyAlgorithm::DSA
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::EC
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA1,
key_alg: PubKeyAlgorithm::EC
@@ -846,6 +1014,10 @@ mod tests {
hash_alg: HashAlgorithm::SHA512,
key_alg: PubKeyAlgorithm::EC
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::None,
key_alg: PubKeyAlgorithm::RSAPSS
},
SignatureAlgorithm {
hash_alg: HashAlgorithm::SHA256,
key_alg: PubKeyAlgorithm::RSAPSS