netdoc: use improved API for parsing ed25519 certificates.
This commit is contained in:
parent
332b9de542
commit
60adff1fd7
|
@ -7,13 +7,14 @@
|
|||
|
||||
pub use b64impl::*;
|
||||
pub use curve25519impl::*;
|
||||
pub use edcert::*;
|
||||
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[..])
|
||||
fn from_bytes(b: &[u8], p: crate::Pos) -> crate::Result<Self>;
|
||||
fn from_vec(v: Vec<u8>, p: crate::Pos) -> crate::Result<Self> {
|
||||
Self::from_bytes(&v[..], p)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +106,7 @@ mod rsa {
|
|||
|
||||
/// An RSA public key, as parsed from a base64-encoded object.
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct RSAPublic(PublicKey);
|
||||
pub struct RSAPublic(PublicKey, Pos);
|
||||
|
||||
impl From<RSAPublic> for PublicKey {
|
||||
fn from(k: RSAPublic) -> PublicKey {
|
||||
|
@ -113,11 +114,11 @@ mod rsa {
|
|||
}
|
||||
}
|
||||
impl super::FromBytes for RSAPublic {
|
||||
fn from_bytes(b: &[u8]) -> Result<Self> {
|
||||
fn from_bytes(b: &[u8], pos: Pos) -> 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))
|
||||
Ok(RSAPublic(key, pos))
|
||||
}
|
||||
}
|
||||
impl RSAPublic {
|
||||
|
@ -126,10 +127,7 @@ mod rsa {
|
|||
if self.0.exponent_is(e) {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(Error::BadObjectVal(
|
||||
Pos::None,
|
||||
"invalid RSA exponent".into(),
|
||||
))
|
||||
Err(Error::BadObjectVal(self.1, "invalid RSA exponent".into()))
|
||||
}
|
||||
}
|
||||
/// Give an error if the exponent of this key is not contained in 'bounds'
|
||||
|
@ -137,7 +135,7 @@ mod rsa {
|
|||
if bounds.contains(&self.0.bits()) {
|
||||
Ok(self)
|
||||
} else {
|
||||
Err(Error::BadObjectVal(Pos::None, "invalid RSA length".into()))
|
||||
Err(Error::BadObjectVal(self.1, "invalid RSA length".into()))
|
||||
}
|
||||
}
|
||||
pub fn check_len_eq(self, n: usize) -> Result<Self> {
|
||||
|
@ -145,3 +143,60 @@ mod rsa {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod edcert {
|
||||
use crate::{Error, Pos, Result};
|
||||
use tor_cert::Ed25519Cert;
|
||||
use tor_llcrypto::pk::ed25519;
|
||||
|
||||
/// An ed25519 certificate as parsed from a directory object, with
|
||||
/// signature not validated.
|
||||
pub struct UnvalidatedEdCert(Vec<u8>, Pos);
|
||||
|
||||
/// An ed25519 certificate as parsed from a directory object, with
|
||||
/// checked signature.
|
||||
pub struct ValidatedEdCert(Ed25519Cert, Pos);
|
||||
impl From<ValidatedEdCert> for Ed25519Cert {
|
||||
fn from(c: ValidatedEdCert) -> Self {
|
||||
c.0
|
||||
}
|
||||
}
|
||||
impl super::FromBytes for UnvalidatedEdCert {
|
||||
fn from_bytes(b: &[u8], p: Pos) -> Result<Self> {
|
||||
Self::from_vec(b.into(), p)
|
||||
}
|
||||
fn from_vec(v: Vec<u8>, p: Pos) -> Result<Self> {
|
||||
Ok(Self(v, p))
|
||||
}
|
||||
}
|
||||
impl UnvalidatedEdCert {
|
||||
pub fn validate(self, signing_key: Option<&ed25519::PublicKey>) -> Result<ValidatedEdCert> {
|
||||
let cert = Ed25519Cert::decode_and_check(&self.0, signing_key)
|
||||
.map_err(|e| Error::BadObjectVal(self.1, e.to_string()))?;
|
||||
Ok(ValidatedEdCert(cert, self.1))
|
||||
}
|
||||
}
|
||||
impl ValidatedEdCert {
|
||||
/// Give an error if this certificate's type is not `desired_type`.
|
||||
pub fn check_cert_type(self, desired_type: u8) -> Result<Self> {
|
||||
if self.0.get_cert_type() != desired_type {
|
||||
return Err(Error::BadObjectVal(
|
||||
self.1,
|
||||
format!(
|
||||
"bad certificate type {} (wanted {})",
|
||||
self.0.get_cert_type(),
|
||||
desired_type
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
/// Give an error if this certificate's subject_key is not `pk`
|
||||
pub fn check_subject_key_is(self, pk: &ed25519::PublicKey) -> Result<Self> {
|
||||
if self.0.get_subject_key().as_ed25519() != Some(pk) {
|
||||
return Err(Error::BadObjectVal(self.1, "incorrect subject key".into()));
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -295,15 +295,11 @@ impl RouterDesc {
|
|||
if cert_tok.offset_in(s).unwrap() < start_offset {
|
||||
return Err(Error::MisplacedToken("identity-ed25519", cert_tok.pos()));
|
||||
}
|
||||
let cert = cert_tok.get_obj("ED25519 CERT")?;
|
||||
let cert = tor_cert::Ed25519Cert::decode_and_check(&cert[..], None)
|
||||
.map_err(|_| Error::BadSignature(cert_tok.pos()))?;
|
||||
if cert.get_cert_type() != tor_cert::certtype::IDENTITY_V_SIGNING {
|
||||
return Err(Error::BadObjectVal(
|
||||
cert_tok.pos(),
|
||||
"wrong certificate type".to_string(),
|
||||
));
|
||||
}
|
||||
let cert: tor_cert::Ed25519Cert = cert_tok
|
||||
.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
|
||||
.validate(None)?
|
||||
.check_cert_type(tor_cert::certtype::IDENTITY_V_SIGNING)?
|
||||
.into();
|
||||
let sk = cert.get_subject_key().as_ed25519().ok_or_else(|| {
|
||||
Error::BadObjectVal(cert_tok.pos(), "no ed25519 signing key".to_string())
|
||||
})?;
|
||||
|
@ -403,24 +399,18 @@ impl RouterDesc {
|
|||
// Technically required? XXXX
|
||||
let cc = body.get_required(NTOR_ONION_KEY_CROSSCERT)?;
|
||||
let sign: u8 = cc.parse_arg(0)?;
|
||||
let cert = cc.get_obj("ED25519 CERT")?;
|
||||
if sign != 0 && sign != 1 {
|
||||
return Err(Error::BadArgument(cc.pos(), "not 0 or 1".to_string()));
|
||||
return Err(Error::BadArgument(cc.arg_pos(0), "not 0 or 1".to_string()));
|
||||
}
|
||||
let ntor_as_ed =
|
||||
ll::pk::keymanip::convert_curve25519_to_ed25519_public(&ntor_onion_key, sign)
|
||||
.ok_or_else(|| Error::Internal(cc.pos()))?; // XXX not really 'internal'
|
||||
let crosscert = tor_cert::Ed25519Cert::decode_and_check(&cert[..], Some(&ntor_as_ed))
|
||||
.map_err(|_| Error::BadSignature(cc.pos()))?;
|
||||
if crosscert.get_cert_type() != tor_cert::certtype::NTOR_CC_IDENTITY {
|
||||
return Err(Error::BadObjectVal(
|
||||
cc.pos(),
|
||||
"wrong certificate type".into(),
|
||||
));
|
||||
}
|
||||
if crosscert.get_subject_key().as_ed25519() != Some(identity_cert.get_signing_key()) {
|
||||
return Err(Error::BadSignature(cc.pos()));
|
||||
}
|
||||
let crosscert: tor_cert::Ed25519Cert = cc
|
||||
.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
|
||||
.validate(Some(&ntor_as_ed))?
|
||||
.check_cert_type(tor_cert::certtype::NTOR_CC_IDENTITY)?
|
||||
.check_subject_key_is(identity_cert.get_signing_key())?
|
||||
.into();
|
||||
expiry = std::cmp::min(expiry, crosscert.get_expiry());
|
||||
}
|
||||
|
||||
|
|
|
@ -326,7 +326,8 @@ impl<'a> Item<'a> {
|
|||
/// 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)))
|
||||
let p = Pos::at(self.object.unwrap().data);
|
||||
V::from_vec(bytes, p).map_err(|e| e.at_pos(p))
|
||||
}
|
||||
/// Return the position of this item.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue