#![forbid(missing_docs)]
use alloc::vec::Vec;
#[cfg(feature = "num-bigint")]
use num_bigint::{BigUint, BigInt};
#[cfg(feature = "bit-vec")]
use bit_vec::BitVec;
use super::{PCBit, Tag};
use super::tags::{TAG_BOOLEAN,TAG_INTEGER,TAG_OCTETSTRING};
use super::tags::{TAG_NULL,TAG_OID,TAG_UTF8STRING,TAG_SEQUENCE,TAG_SET,TAG_ENUM,TAG_IA5STRING,TAG_BMPSTRING};
use super::tags::{TAG_NUMERICSTRING,TAG_PRINTABLESTRING,TAG_VISIBLESTRING};
use super::models::{ObjectIdentifier,TaggedDerValue};
#[cfg(feature = "time")]
use super::models::{UTCTime,GeneralizedTime};
pub fn construct_der<F>(callback: F) -> Vec<u8>
where F: FnOnce(DERWriter) {
let mut buf = Vec::new();
{
let mut writer = DERWriterSeq {
buf: &mut buf,
};
callback(writer.next());
}
return buf;
}
pub fn try_construct_der<F, E>(callback: F) -> Result<Vec<u8>, E>
where F: FnOnce(DERWriter) -> Result<(), E> {
let mut buf = Vec::new();
{
let mut writer = DERWriterSeq {
buf: &mut buf,
};
callback(writer.next())?;
}
return Ok(buf);
}
pub fn construct_der_seq<F>(callback: F) -> Vec<u8>
where F: FnOnce(&mut DERWriterSeq) {
let mut buf = Vec::new();
{
let mut writer = DERWriterSeq {
buf: &mut buf,
};
callback(&mut writer);
}
return buf;
}
pub fn try_construct_der_seq<F, E>(callback: F) -> Result<Vec<u8> , E>
where F: FnOnce(&mut DERWriterSeq) -> Result<(), E> {
let mut buf = Vec::new();
{
let mut writer = DERWriterSeq {
buf: &mut buf,
};
callback(&mut writer)?;
}
return Ok(buf);
}
#[derive(Debug)]
pub struct DERWriter<'a> {
buf: &'a mut Vec<u8>,
implicit_tag: Option<Tag>,
}
impl<'a> DERWriter<'a> {
fn from_buf(buf: &'a mut Vec<u8>) -> Self {
return DERWriter {
buf,
implicit_tag: None,
}
}
fn write_identifier(&mut self, tag: Tag, pc: PCBit) {
let tag = if let Some(tag) = self.implicit_tag { tag } else { tag };
self.implicit_tag = None;
let classid = tag.tag_class as u8;
let pcid = pc as u8;
if tag.tag_number < 31 {
self.buf.push(
(classid << 6) | (pcid << 5) | (tag.tag_number as u8));
return;
}
self.buf.push((classid << 6) | (pcid << 5) | 31);
let mut shiftnum = 63; while (tag.tag_number >> shiftnum) == 0 {
shiftnum -= 7;
}
while shiftnum > 0 {
self.buf.push(128 | (((tag.tag_number >> shiftnum) & 127) as u8));
shiftnum -= 7;
}
self.buf.push((tag.tag_number & 127) as u8);
}
fn write_length(&mut self, length: usize) {
let length = length as u64;
if length < 128 {
self.buf.push(length as u8);
return;
}
let mut shiftnum = 56; while (length >> shiftnum) == 0 {
shiftnum -= 8;
}
self.buf.push(128 | ((shiftnum / 8 + 1) as u8));
loop {
self.buf.push((length >> shiftnum) as u8);
if shiftnum == 0 {
break;
}
shiftnum -= 8;
}
}
fn with_length<T, F>(&mut self, callback: F) -> T
where F: FnOnce(&mut Self) -> T {
let expected_length_length = 3;
for _ in 0..3 {
self.buf.push(255);
}
let start_pos = self.buf.len();
let result = callback(self);
let length = (self.buf.len() - start_pos) as u64;
let length_length;
let mut shiftnum = 56; if length < 128 {
length_length = 1;
} else {
while (length >> shiftnum) == 0 {
shiftnum -= 8;
}
length_length = shiftnum / 8 + 2;
}
let new_start_pos;
if length_length < expected_length_length {
let diff = expected_length_length - length_length;
new_start_pos = start_pos - diff;
self.buf.drain(new_start_pos .. start_pos);
} else if length_length > expected_length_length {
let diff = length_length - expected_length_length;
new_start_pos = start_pos + diff;
for _ in 0..diff { self.buf.insert(start_pos, 0); }
} else {
new_start_pos = start_pos;
}
let mut idx = new_start_pos - length_length;
if length < 128 {
self.buf[idx] = length as u8;
} else {
self.buf[idx] = 128 | ((shiftnum / 8 + 1) as u8);
idx += 1;
loop {
self.buf[idx] = (length >> shiftnum) as u8;
idx += 1;
if shiftnum == 0 {
break;
}
shiftnum -= 8;
}
}
return result;
}
pub fn write_bool(mut self, val: bool) {
self.write_identifier(TAG_BOOLEAN, PCBit::Primitive);
self.write_length(1);
self.buf.push(if val { 255 } else { 0 });
}
fn write_integer(mut self, tag: Tag, val: i64) {
let mut shiftnum = 56;
while shiftnum > 0 &&
(val >> (shiftnum-1) == 0 || val >> (shiftnum-1) == -1) {
shiftnum -= 8;
}
self.write_identifier(tag, PCBit::Primitive);
self.write_length(shiftnum / 8 + 1);
loop {
self.buf.push((val >> shiftnum) as u8);
if shiftnum == 0 {
break;
}
shiftnum -= 8;
}
}
pub fn write_enum(self, val: i64) {
self.write_integer(TAG_ENUM, val);
}
pub fn write_i64(self, val: i64) {
self.write_integer(TAG_INTEGER, val);
}
pub fn write_u64(mut self, val: u64) {
let mut shiftnum = 64;
while shiftnum > 0 && val >> (shiftnum-1) == 0 {
shiftnum -= 8;
}
self.write_identifier(TAG_INTEGER, PCBit::Primitive);
self.write_length(shiftnum / 8 + 1);
if shiftnum == 64 {
self.buf.push(0);
shiftnum -= 8;
}
loop {
self.buf.push((val >> shiftnum) as u8);
if shiftnum == 0 {
break;
}
shiftnum -= 8;
}
}
pub fn write_i32(self, val: i32) {
self.write_i64(val as i64)
}
pub fn write_u32(self, val: u32) {
self.write_i64(val as i64)
}
pub fn write_i16(self, val: i16) {
self.write_i64(val as i64)
}
pub fn write_u16(self, val: u16) {
self.write_i64(val as i64)
}
pub fn write_i8(self, val: i8) {
self.write_i64(val as i64)
}
pub fn write_u8(self, val: u8) {
self.write_i64(val as i64)
}
#[cfg(feature = "num-bigint")]
pub fn write_bigint(self, val: &BigInt) {
use num_bigint::Sign;
let (sign, mut bytes) = val.to_bytes_be();
if sign == Sign::Minus {
let mut carry: usize = 1;
for b in bytes.iter_mut().rev() {
let bval = 255 - (*b as usize);
*b = (bval + carry) as u8;
carry = (bval + carry) >> 8;
}
}
self.write_bigint_bytes(&bytes, sign != Sign::Minus);
}
pub fn write_bigint_bytes(mut self, bytes: &[u8], positive: bool) {
let mut bytes = bytes;
while bytes.get(0) == Some(&0) {
bytes = &bytes[1..];
}
if !positive {
while bytes.len() > 1 && bytes[0] == 255 && bytes.get(1).unwrap_or(&0) & 128 != 0 {
bytes = &bytes[1..];
}
}
self.write_identifier(TAG_INTEGER, PCBit::Primitive);
if bytes.len() == 0 || bytes[0] == 0 {
self.write_length(1);
self.buf.push(0);
} else if positive {
if bytes[0] >= 128 {
self.write_length(bytes.len() + 1);
self.buf.push(0);
} else {
self.write_length(bytes.len());
}
self.buf.extend_from_slice(&bytes);
} else {
debug_assert!(bytes[0] != 0);
if bytes[0] < 128 {
self.write_length(bytes.len() + 1);
self.buf.push(255);
} else {
self.write_length(bytes.len());
}
self.buf.extend_from_slice(&bytes);
}
}
#[cfg(feature = "num-bigint")]
pub fn write_biguint(mut self, val: &BigUint) {
self.write_identifier(TAG_INTEGER, PCBit::Primitive);
let mut bytes = val.to_bytes_le();
if &bytes == &[0] {
self.write_length(1);
self.buf.push(0);
return;
}
let byteslen = bytes.len();
debug_assert!(bytes[byteslen-1] != 0);
if bytes[byteslen-1] >= 128 {
self.write_length(byteslen+1);
self.buf.push(0);
} else {
self.write_length(byteslen);
}
bytes.reverse();
self.buf.extend_from_slice(&bytes);
}
#[cfg(feature = "bit-vec")]
pub fn write_bitvec(self, bitvec: &BitVec) {
let len = bitvec.len();
let bytes = bitvec.to_bytes();
self.write_bitvec_bytes(&bytes, len);
}
pub fn write_bitvec_bytes(mut self, bytes: &[u8], len: usize) {
use super::tags::TAG_BITSTRING;
self.write_identifier(TAG_BITSTRING, PCBit::Primitive);
debug_assert!(len <= 8 * bytes.len());
debug_assert!(8 * bytes.len() < len + 8);
self.write_length(1 + bytes.len());
let len_diff = 8 * bytes.len() - len;
self.buf.push(len_diff as u8);
if bytes.len() > 0 {
self.buf.extend_from_slice(&bytes[0 .. bytes.len() - 1]);
let mask = !(255u16 >> (8 - len_diff)) as u8;
self.buf.push(bytes[bytes.len() - 1] & mask);
}
}
pub fn write_bytes(mut self, bytes: &[u8]) {
self.write_identifier(TAG_OCTETSTRING, PCBit::Primitive);
self.write_length(bytes.len());
self.buf.extend_from_slice(bytes);
}
pub fn write_utf8_string(mut self, string: &str) {
self.write_identifier(TAG_UTF8STRING, PCBit::Primitive);
self.write_length(string.len());
self.buf.extend_from_slice(string.as_bytes());
}
pub fn write_ia5_string(mut self, string: &str) {
assert!(string.is_ascii(), "IA5 string must be ASCII");
self.write_identifier(TAG_IA5STRING, PCBit::Primitive);
self.write_length(string.len());
self.buf.extend_from_slice(string.as_bytes());
}
pub fn write_bmp_string(mut self, string: &str) {
let utf16 : Vec<u16> = string.encode_utf16().collect();
let mut bytes = Vec::with_capacity(utf16.len() * 2);
for c in utf16 {
bytes.push((c / 256) as u8);
bytes.push((c % 256) as u8);
}
self.write_identifier(TAG_BMPSTRING, PCBit::Primitive);
self.write_length(bytes.len());
self.buf.extend_from_slice(&bytes);
}
pub fn write_null(mut self) {
self.write_identifier(TAG_NULL, PCBit::Primitive);
self.write_length(0);
}
pub fn write_oid(mut self, oid: &ObjectIdentifier) {
assert!(oid.components().len() >= 2, "Invalid OID: too short");
let id0 = oid.components()[0];
let id1 = oid.components()[1];
assert!(
(id0 < 3) && (id1 < 18446744073709551535) &&
(id0 >= 2 || id1 < 40),
"Invalid OID {{{} {} ...}}", id0, id1);
let subid0 = id0 * 40 + id1;
let mut length = 0;
for i in 1..oid.components().len() {
let mut subid = if i == 1 {
subid0
} else {
oid.components()[i]
} | 1;
while subid > 0 {
length += 1;
subid >>= 7;
}
}
self.write_identifier(TAG_OID, PCBit::Primitive);
self.write_length(length);
for i in 1..oid.components().len() {
let subid = if i == 1 {
subid0
} else {
oid.components()[i]
};
let mut shiftnum = 63; while ((subid|1) >> shiftnum) == 0 {
shiftnum -= 7;
}
while shiftnum > 0 {
self.buf.push(128 | ((((subid|1) >> shiftnum) & 127) as u8));
shiftnum -= 7;
}
self.buf.push((subid & 127) as u8);
}
}
pub fn write_utf8string(self, string: &str) {
self.write_tagged_implicit(TAG_UTF8STRING, |writer| {
writer.write_bytes(string.as_bytes())
})
}
pub fn write_sequence<T, F>(mut self, callback: F) -> T
where F: FnOnce(&mut DERWriterSeq) -> T {
self.write_identifier(TAG_SEQUENCE, PCBit::Constructed);
return self.with_length(|writer| {
callback(&mut DERWriterSeq {
buf: writer.buf,
})
});
}
pub fn write_sequence_of<T, F>(self, callback: F) -> T
where F: FnOnce(&mut DERWriterSeq) -> T {
self.write_sequence(callback)
}
pub fn write_set<T, F>(mut self, callback: F) -> T
where F: FnOnce(&mut DERWriterSet) -> T {
let mut bufs = Vec::new();
let result = callback(&mut DERWriterSet {
bufs: &mut bufs,
});
for buf in bufs.iter() {
assert!(buf.len() > 0, "Empty output in write_set()");
}
bufs.sort_by(|buf0, buf1| {
let buf00 = buf0[0] & 223;
let buf10 = buf1[0] & 223;
if buf00 != buf10 || (buf0[0] & 31) != 31 {
return buf00.cmp(&buf10);
}
let len0 = buf0[1..].iter().position(|x| x & 128 == 0).unwrap();
let len1 = buf1[1..].iter().position(|x| x & 128 == 0).unwrap();
if len0 != len1 {
return len0.cmp(&len1);
}
return buf0[1..].cmp(&buf1[1..]);
});
let bufs_len = bufs.iter().map(|buf| buf.len()).fold(0, |x, y| x + y);
self.write_identifier(TAG_SET, PCBit::Constructed);
self.write_length(bufs_len);
for buf in bufs.iter() {
self.buf.extend_from_slice(buf);
}
return result;
}
pub fn write_set_of<T, F>(mut self, callback: F) -> T
where F: FnOnce(&mut DERWriterSet) -> T {
let mut bufs = Vec::new();
let result = callback(&mut DERWriterSet {
bufs: &mut bufs,
});
for buf in bufs.iter() {
assert!(buf.len() > 0, "Empty output in write_set_of()");
}
bufs.sort();
let bufs_len = bufs.iter().map(|buf| buf.len()).fold(0, |x, y| x + y);
self.write_identifier(TAG_SET, PCBit::Constructed);
self.write_length(bufs_len);
for buf in bufs.iter() {
self.buf.extend_from_slice(buf);
}
return result;
}
pub fn write_numeric_string(self, string: &str) {
let bytes = string.as_bytes();
for &byte in bytes {
assert!(byte == b' ' || (b'0' <= byte && byte <= b'9'),
"Invalid NumericString: {:?} appeared", byte);
}
self.write_tagged_implicit(TAG_NUMERICSTRING, |writer| {
writer.write_bytes(bytes)
});
}
pub fn write_printable_string(self, string: &str) {
let bytes = string.as_bytes();
for &byte in bytes {
assert!(
byte == b' ' ||
(b'\'' <= byte && byte <= b':' && byte != b'*') ||
byte == b'=' ||
(b'A' <= byte && byte <= b'Z') ||
(b'a' <= byte && byte <= b'z'),
"Invalid PrintableString: {:?} appeared", byte);
}
self.write_tagged_implicit(TAG_PRINTABLESTRING, |writer| {
writer.write_bytes(bytes)
});
}
#[cfg(feature = "time")]
pub fn write_utctime(self, datetime: &UTCTime) {
use super::tags::TAG_UTCTIME;
self.write_tagged_implicit(TAG_UTCTIME, |writer| {
writer.write_bytes(&datetime.to_bytes())
});
}
#[cfg(feature = "time")]
pub fn write_generalized_time(self, datetime: &GeneralizedTime) {
use super::tags::TAG_GENERALIZEDTIME;
self.write_tagged_implicit(TAG_GENERALIZEDTIME, |writer| {
writer.write_bytes(&datetime.to_bytes())
});
}
pub fn write_visible_string(self, string: &str) {
let bytes = string.as_bytes();
for &byte in bytes {
assert!(b' ' <= byte && byte <= b'~',
"Invalid VisibleString: {:?} appeared", byte);
}
self.write_tagged_implicit(TAG_VISIBLESTRING, |writer| {
writer.write_bytes(bytes)
});
}
pub fn write_tagged<T, F>(mut self, tag: Tag, callback: F) -> T
where F: FnOnce(DERWriter) -> T {
self.write_identifier(tag, PCBit::Constructed);
return self.with_length(|writer| {
callback(DERWriter::from_buf(writer.buf))
});
}
pub fn write_tagged_implicit<T, F>
(mut self, tag: Tag, callback: F) -> T
where F: FnOnce(DERWriter) -> T {
let tag = if let Some(tag) = self.implicit_tag { tag } else { tag };
self.implicit_tag = None;
let mut writer = DERWriter::from_buf(self.buf);
writer.implicit_tag = Some(tag);
return callback(writer);
}
pub fn write_tagged_der(mut self, der: &TaggedDerValue) {
self.write_identifier(der.tag(), der.pcbit());
self.write_length(der.value().len());
self.buf.extend_from_slice(der.value());
}
pub fn write_der(self, der: &[u8]) {
self.buf.extend_from_slice(der);
}
}
#[derive(Debug)]
pub struct DERWriterSeq<'a> {
buf: &'a mut Vec<u8>,
}
impl<'a> DERWriterSeq<'a> {
pub fn next<'b>(&'b mut self) -> DERWriter<'b> {
return DERWriter::from_buf(self.buf);
}
}
#[derive(Debug)]
pub struct DERWriterSet<'a> {
bufs: &'a mut Vec<Vec<u8>>,
}
impl<'a> DERWriterSet<'a> {
pub fn next<'b>(&'b mut self) -> DERWriter<'b> {
self.bufs.push(Vec::new());
return DERWriter::from_buf(self.bufs.last_mut().unwrap());
}
}
#[cfg(test)]
mod tests;