Compare commits

..

3 Commits

Author SHA1 Message Date
occheung eadf776da3 fix tab/space 2020-10-21 18:18:54 +08:00
occheung 5986777770 parse: add ASN1 DER 2020-10-21 18:18:41 +08:00
occheung 2b107881d8 certificate: init 2020-10-21 18:17:55 +08:00
10 changed files with 1867 additions and 1686 deletions

View File

@ -12,6 +12,7 @@ num_enum = { version = "0.5.1", default-features = false }
log = "0.4.11" log = "0.4.11"
generic-array = "0.14.4" generic-array = "0.14.4"
heapless = "0.5.6" heapless = "0.5.6"
asn1_der = { version = "0.7.1", features = [ "native_types", "no_std" ] }
[dependencies.aes-gcm] [dependencies.aes-gcm]
version = "0.8.0" version = "0.8.0"

54
src/certificate.rs Normal file
View File

@ -0,0 +1,54 @@
use num_enum::IntoPrimitive;
use num_enum::TryFromPrimitive;
pub struct Certificate<'a> {
tbs_certificate: TBSCertificate<'a>,
signature_algorithm: AlgorithmIdentifier<'a>,
signature_value: &'a [u8]
}
pub struct TBSCertificate<'a> {
version: Version,
serial_number: &'a [u8],
signature: AlgorithmIdentifier<'a>,
issuer: &'a [u8],
validity: Validity<'a>,
subject: &'a [u8],
subject_public_key_info: SubjectPublicKeyInfo<'a>,
issuer_unique_id: Option<&'a [u8]>,
subject_unique_id: Option<&'a [u8]>,
extensions: Extensions,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum Version {
#[num_enum(default)]
v1 = 0,
v2 = 1,
v3 = 2,
}
pub struct Validity<'a> {
not_before: Time<'a>,
not_after: Time<'a>,
}
pub enum Time<'a> {
UTCTime(&'a [u8]),
GeneralizedTime(&'a [u8]),
}
pub struct SubjectPublicKeyInfo<'a> {
algorithm: AlgorithmIdentifier<'a>,
subject_public_key: &'a [u8],
}
pub struct Extensions {
}
pub struct AlgorithmIdentifier<'a> {
pub algorithm: &'a [u8],
pub parameters: &'a [u8],
}

View File

@ -9,12 +9,15 @@ pub mod parse;
pub mod buffer; pub mod buffer;
pub mod key; pub mod key;
pub mod session; pub mod session;
pub mod certificate;
use nom::error::ParseError;
// TODO: Implement errors // TODO: Implement errors
// Details: Encapsulate smoltcp & nom errors // Details: Encapsulate smoltcp & nom errors
pub enum Error { pub enum Error {
PropagatedError(smoltcp::Error), PropagatedError(smoltcp::Error),
ParsingError, ParsingError(nom::error::ErrorKind),
EncryptionError, EncryptionError,
DecryptionError, DecryptionError,
CapacityError, CapacityError,

View File

@ -22,11 +22,10 @@ use hkdf::Hkdf;
use smoltcp_tls::key::*; use smoltcp_tls::key::*;
use smoltcp_tls::buffer::TlsBuffer; use smoltcp_tls::buffer::TlsBuffer;
use asn1_der::{ use smoltcp_tls::certificate::*;
DerObject,
typed::{ DerEncodable, DerDecodable }
};
use asn1_der::DerObject;
use smoltcp_tls::parse::*;
struct CountingRng(u64); struct CountingRng(u64);
@ -78,14 +77,14 @@ fn main() {
).unwrap(); ).unwrap();
// tls_socket.tls_connect(&mut sockets).unwrap(); // tls_socket.tls_connect(&mut sockets).unwrap();
let object = DerObject::decode(&CERT).expect("Failed to decode object"); let (rest, result) = parse_asn1_der_certificate(&CERT).unwrap();
println!("raw: {:2X?},\nheader: {:2X?},\ntag: {:2X?},\nvalue: {:2X?}\n", println!(
object.raw(), "{:X?}\n{:X?}\n{:X?}\n{:X?}",
object.header(), rest,
object.tag(), result.0,
object.value() result.1,
result.2
); );
} }
const CERT: [u8; 805] = [ const CERT: [u8; 805] = [

View File

@ -5,6 +5,7 @@ use nom::bytes::complete::take_till;
use nom::combinator::complete; use nom::combinator::complete;
use nom::sequence::preceded; use nom::sequence::preceded;
use nom::sequence::tuple; use nom::sequence::tuple;
use nom::error::make_error;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use smoltcp::Error; use smoltcp::Error;
use smoltcp::Result; use smoltcp::Result;
@ -12,7 +13,18 @@ use smoltcp::Result;
use byteorder::{ByteOrder, NetworkEndian, BigEndian}; use byteorder::{ByteOrder, NetworkEndian, BigEndian};
use crate::tls_packet::*; use crate::tls_packet::*;
use crate::certificate::Certificate as Asn1DerCertificate;
use crate::certificate::Version as Asn1DerVersion;
use crate::certificate::AlgorithmIdentifier as Asn1DerAlgId;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::convert::TryInto;
use asn1_der::{
DerObject,
typed::{ DerEncodable, DerDecodable },
Asn1DerError,
};
use alloc::vec::Vec; use alloc::vec::Vec;
@ -327,3 +339,115 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
} }
)) ))
} }
pub fn parse_asn1_der_header(bytes: &[u8]) -> IResult<&[u8], (u8, usize)> {
// Parse tag
let (rest, tag) = take(1_usize)(bytes)?;
// Parse length
let (rest, length_byte) = take(1_usize)(rest)?;
if length_byte[0] <= 0x7F {
Ok((rest, (tag[0], length_byte[0].into())))
} else {
if length_byte[0] & 0x7F > core::mem::size_of::<usize>().try_into().unwrap() {
return Err(nom::Err::Failure((length_byte, ErrorKind::TooLarge)));
}
let length_size = length_byte[0] & 0x7F;
let (rem, length_slice) = take(length_size)(rest)?;
let mut length_array: [u8; 8] = [0; 8];
for array_index in 0..length_slice.len() {
length_array[array_index + 8 - length_slice.len()] = length_slice[array_index];
}
Ok((rem, (tag[0], usize::from_be_bytes(length_array))))
}
}
pub fn parse_asn1_der_object(bytes: &[u8]) -> IResult<&[u8], (u8, usize, &[u8])> {
let (rest, (tag, length)) = parse_asn1_der_header(bytes)?;
let (rest, value) = take(length)(rest)?;
Ok((rest, (tag, length, value)))
}
pub fn parse_asn1_der_certificate(bytes: &[u8]) -> IResult<&[u8], (&[u8], &[u8], &[u8])> {
let (_, (_, _, rest)) = parse_asn1_der_object(bytes)?;
let (rest, (_, _, tbscertificate_slice)) = parse_asn1_der_object(rest)?;
let (rest, (_, _, signature_alg)) = parse_asn1_der_object(rest)?;
let (rest, (_, _, sig_val)) = parse_asn1_der_object(rest)?;
Ok((rest, (tbscertificate_slice, signature_alg, sig_val)))
}
pub fn parse_asn1_der_tbs_certificate(bytes: &[u8]) -> IResult<&[u8], Vec<&[u8]>> {
todo!()
}
// version: [0] EXPLICIT Version DEFAULT V1
// Version encapsulates an Integer
// i.e. context-specific, constructed, type [0] -> tag: A0
pub fn parse_asn1_der_version(bytes: &[u8]) -> IResult<&[u8], Asn1DerVersion> {
let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?;
// Verify the tag is indeed 0xA0
if tag_val != 0xA0 {
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
}
// Parse the encapsulated INTEGER, force completeness
let (_, integer) = complete(parse_asn1_der_integer)(value)?;
// Either 0, 1, or 2, take the last byte and assert all former bytes to be 0
let (zeroes, version_byte) = take(integer.len()-1)(integer)?;
complete(take_till(|byte| byte != 0))(zeroes)?;
Ok((rest, Asn1DerVersion::try_from(version_byte[0]).unwrap()))
}
// INTEGER: tag: 0x02
pub fn parse_asn1_der_integer(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?;
// Verify the tag is indeed 0x02
if tag_val != 0x02 {
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
}
Ok((rest, value))
}
// CertificateSerialNumber: alias of INTEGER
pub fn parse_asn1_der_serial_number(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
parse_asn1_der_integer(bytes)
}
// Algorithm Identifier: Sequence -> universal, constructed, 0 (0x30)
// Encapsulates OID (alg) and optional params (params)
pub fn parse_asn1_der_algorithm_identifier(bytes: &[u8]) -> IResult<&[u8], Asn1DerAlgId> {
let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?;
// Verify the tag_val is indeed 0x30
if tag_val != 0x30 {
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
}
// Parse OID and then optionl parameters
let (_, (oid, (_, _, optional_param))) = complete(
tuple((
parse_asn1_der_oid,
parse_asn1_der_object
))
)(value)?;
Ok((
rest,
Asn1DerAlgId {
algorithm: oid,
parameters: optional_param,
}
))
}
// Parser for Universal OID type (0x06)
pub fn parse_asn1_der_oid(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?;
// Verify the tag_val is indeed 0x06
if tag_val != 0x06 {
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
}
Ok((rest, value))
}
// Parser for Time Validity Structure
pub fn parse_asn1_der_validity(bytes: &[u8]) -> IResult<&[u8], &[u8]> {
let (rest, (tag_val, length, value)) = parse_asn1_der_object(bytes)?;
}