Netdoc: better parsing for objects.

If I'm right this will let us simplify our code for parsing things
from directory objects by a lot.
This commit is contained in:
Nick Mathewson 2020-05-15 11:18:04 -04:00
parent 9b581588d6
commit f6dd702316
2 changed files with 63 additions and 0 deletions

View File

@ -7,8 +7,16 @@
pub use b64impl::*;
pub use curve25519impl::*;
pub use rsa::*;
pub use timeimpl::*;
pub trait FromBytes: Sized {
fn from_bytes(b: &[u8]) -> crate::Result<Self>;
fn from_vec(v: Vec<u8>) -> crate::Result<Self> {
Self::from_bytes(&v[..])
}
}
mod b64impl {
use crate::{Error, Pos, Result};
@ -89,3 +97,51 @@ mod timeimpl {
}
}
}
mod rsa {
use crate::{Error, Pos, Result};
use std::ops::RangeBounds;
use tor_llcrypto::pk::rsa::PublicKey;
/// An RSA public key, as parsed from a base64-encoded object.
#[allow(non_camel_case_types)]
pub struct RSAPublic(PublicKey);
impl From<RSAPublic> for PublicKey {
fn from(k: RSAPublic) -> PublicKey {
k.0
}
}
impl super::FromBytes for RSAPublic {
fn from_bytes(b: &[u8]) -> Result<Self> {
let key = PublicKey::from_der(b).ok_or_else(|| {
Error::BadObjectVal(Pos::None, "unable to decode RSA public key".into())
})?;
Ok(RSAPublic(key))
}
}
impl RSAPublic {
/// Give an error if the exponent of this key is not 'e'
pub fn check_exponent(self, e: u32) -> Result<Self> {
if self.0.exponent_is(e) {
Ok(self)
} else {
Err(Error::BadObjectVal(
Pos::None,
"invalid RSA exponent".into(),
))
}
}
/// Give an error if the exponent of this key is not contained in 'bounds'
pub fn check_len<B: RangeBounds<usize>>(self, bounds: B) -> Result<Self> {
if bounds.contains(&self.0.bits()) {
Ok(self)
} else {
Err(Error::BadObjectVal(Pos::None, "invalid RSA length".into()))
}
}
pub fn check_len_eq(self, n: usize) -> Result<Self> {
self.check_len(n..=n)
}
}
}

View File

@ -4,6 +4,7 @@
//! directory document, and NetDocReader, which is used to break a
//! string into Items.
use crate::argtype::FromBytes;
use crate::{Error, Pos, Result};
use std::cell::{Ref, RefCell};
use std::str::FromStr;
@ -321,6 +322,12 @@ impl<'a> Item<'a> {
}
}
}
/// Try to decode the base64 contents of this item's associated object
/// as a given type that implements FromBytes.
pub fn parse_obj<V: FromBytes>(&self, want_tag: &str) -> Result<V> {
let bytes = self.get_obj(want_tag)?;
V::from_vec(bytes).map_err(|e| e.at_pos(Pos::at(self.object.unwrap().data)))
}
/// Return the position of this item.
///
/// This position won't be useful unless it is later contextualized