Compare commits
No commits in common. "eadf776da34ef1f07ca45168766adca729cc858e" and "2e8ccdf910bfe99e3fde20b0aaad5dbf8c1ed122" have entirely different histories.
eadf776da3
...
2e8ccdf910
|
@ -12,7 +12,6 @@ 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"
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
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],
|
|
||||||
}
|
|
|
@ -9,15 +9,12 @@ 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(nom::error::ErrorKind),
|
ParsingError,
|
||||||
EncryptionError,
|
EncryptionError,
|
||||||
DecryptionError,
|
DecryptionError,
|
||||||
CapacityError,
|
CapacityError,
|
||||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -22,10 +22,11 @@ use hkdf::Hkdf;
|
||||||
use smoltcp_tls::key::*;
|
use smoltcp_tls::key::*;
|
||||||
use smoltcp_tls::buffer::TlsBuffer;
|
use smoltcp_tls::buffer::TlsBuffer;
|
||||||
|
|
||||||
use smoltcp_tls::certificate::*;
|
use asn1_der::{
|
||||||
|
DerObject,
|
||||||
|
typed::{ DerEncodable, DerDecodable }
|
||||||
|
};
|
||||||
|
|
||||||
use asn1_der::DerObject;
|
|
||||||
use smoltcp_tls::parse::*;
|
|
||||||
|
|
||||||
struct CountingRng(u64);
|
struct CountingRng(u64);
|
||||||
|
|
||||||
|
@ -77,14 +78,14 @@ fn main() {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
// tls_socket.tls_connect(&mut sockets).unwrap();
|
// tls_socket.tls_connect(&mut sockets).unwrap();
|
||||||
let (rest, result) = parse_asn1_der_certificate(&CERT).unwrap();
|
let object = DerObject::decode(&CERT).expect("Failed to decode object");
|
||||||
println!(
|
println!("raw: {:2X?},\nheader: {:2X?},\ntag: {:2X?},\nvalue: {:2X?}\n",
|
||||||
"{:X?}\n{:X?}\n{:X?}\n{:X?}",
|
object.raw(),
|
||||||
rest,
|
object.header(),
|
||||||
result.0,
|
object.tag(),
|
||||||
result.1,
|
object.value()
|
||||||
result.2
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CERT: [u8; 805] = [
|
const CERT: [u8; 805] = [
|
||||||
|
|
124
src/parse.rs
124
src/parse.rs
|
@ -5,7 +5,6 @@ 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;
|
||||||
|
@ -13,18 +12,7 @@ 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;
|
||||||
|
|
||||||
|
@ -339,115 +327,3 @@ 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)?;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue