tor_cert: use caret_int!() to make real types for cert elements

This commit is contained in:
Nick Mathewson 2020-05-15 16:07:02 -04:00
parent 1bb564024c
commit 085a8250e7
5 changed files with 80 additions and 73 deletions

View File

@ -274,7 +274,9 @@ macro_rules! caret_int {
fn from(num: $numtype) -> $name { $name(num) }
}
impl $name {
$( pub const $id: $name = $name($num) ; )*
$(
$( #[$item_meta] )*
pub const $id: $name = $name($num) ; )*
fn to_str(self) -> Option<&'static str> {
match self {
$( $name::$id => Some(stringify!($id)), )*

View File

@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0"
publish = false
[dependencies]
caret = { path="../caret" }
tor-llcrypto = { path="../tor-llcrypto" }
tor-bytes = { path="../tor-bytes" }

View File

@ -28,6 +28,7 @@
#![deny(missing_docs)]
use caret::caret_int;
use tor_bytes::{Error, Result};
use tor_bytes::{Readable, Reader, Writeable, Writer};
use tor_llcrypto::pk::*;
@ -36,52 +37,58 @@ use tor_llcrypto::pk::*;
// checked" to help with bulk Ed25519 checks. It should be a
// generic trait.
/// Recognized values for Tor's certificate type field.
///
/// In the names used here, "X_V_Y" means "key X verifying key Y",
/// whereas "X_CC_Y" means "key X cros-certifying key Y". In both
/// cases, X is the key that is doing the signing, and Y is the key
/// or object that is getting signed.
pub mod certtype {
// 00 through 03 are reserved.
/// Identity verifying a signing key, directly.
pub const IDENTITY_V_SIGNING: u8 = 0x04;
/// Signing key verifying a TLS certificate by digest.
pub const SIGNING_V_TLS_CERT: u8 = 0x05;
/// Signing key verifying a link authentication key.
pub const SIGNING_V_LINK_AUTH: u8 = 0x06;
// 07 reserved for RSA cross-certification
// 08 through 09 are for onion services.
/// An ntor key converted to a ed25519 key, cross-certifying an
/// identity key.
pub const NTOR_CC_IDENTITY: u8 = 0x0A;
// 0B is for onion services.
}
/// Extension identifiers for extensions in certificates.
pub mod exttype {
/// Extension indicating an Ed25519 key that signed this certificate.
caret_int! {
/// Recognized values for Tor's certificate type field.
///
/// Certificates do not always contain the key that signed them.
pub const SIGNED_WITH_ED25519_KEY: u8 = 0x04;
/// In the names used here, "X_V_Y" means "key X verifying key Y",
/// whereas "X_CC_Y" means "key X cros-certifying key Y". In both
/// cases, X is the key that is doing the signing, and Y is the key
/// or object that is getting signed.
pub struct CertType(u8) {
// 00 through 03 are reserved.
/// Identity verifying a signing key, directly.
IDENTITY_V_SIGNING = 0x04,
/// Signing key verifying a TLS certificate by digest.
SIGNING_V_TLS_CERT = 0x05,
/// Signing key verifying a link authentication key.
SIGNING_V_LINK_AUTH = 0x06,
// 07 reserved for RSA cross-certification
// 08 through 09 are for onion services.
/// An ntor key converted to a ed25519 key, cross-certifying an
/// identity key.
NTOR_CC_IDENTITY = 0x0A,
// 0B is for onion services.
}
}
/// Identifiers for the type of key or object getting signed.
pub mod keytype {
/// Identifier for an Ed25519 key.
pub const ED25519_KEY: u8 = 0x01;
/// Identifier for the SHA256 of an DER-encoded RSA key.
pub const SHA256_OF_RSA: u8 = 0x02;
/// Identifies the SHA256 of an X.509 certificate.
pub const SHA256_OF_X509: u8 = 0x03;
caret_int! {
/// Extension identifiers for extensions in certificates.
pub struct ExtType(u8) {
/// Extension indicating an Ed25519 key that signed this certificate.
///
/// Certificates do not always contain the key that signed them.
SIGNED_WITH_ED25519_KEY = 0x04,
}
}
// 08 through 09 and 0B are used for onion services. They
// probably shouldn't be, but that's what Tor does.
caret_int! {
/// Identifiers for the type of key or object getting signed.
pub struct KeyType(u8) {
/// Identifier for an Ed25519 key.
ED25519_KEY = 0x01,
/// Identifier for the SHA256 of an DER-encoded RSA key.
SHA256_OF_RSA = 0x02,
/// Identifies the SHA256 of an X.509 certificate.
SHA256_OF_X509 = 0x03,
// 08 through 09 and 0B are used for onion services. They
// probably shouldn't be, but that's what Tor does.
}
}
/// Structure for an Ed25519-signed certificate as described in Tor's
@ -90,7 +97,7 @@ pub struct Ed25519Cert {
/// How many _hours_ after the epoch will this certificate expire?
exp_hours: u32,
/// Type of the certificate; recognized values are in certtype::*
cert_type: u8,
cert_type: CertType,
/// The key or object being certified.
cert_key: CertifiedKey,
/// A list of extensions.
@ -114,18 +121,18 @@ pub enum CertifiedKey {
/// A key whose type we didn't recognize.
pub struct UnrecognizedKey {
/// Actual type of the key.
key_type: u8,
key_type: KeyType,
/// digest of the key, or the key itself.
key_digest: [u8; 32],
}
impl CertifiedKey {
/// Return the byte that identifies the type of this key.
pub fn get_key_type(&self) -> u8 {
pub fn get_key_type(&self) -> KeyType {
match self {
CertifiedKey::Ed25519(_) => keytype::ED25519_KEY,
CertifiedKey::RSASha256Digest(_) => keytype::SHA256_OF_RSA,
CertifiedKey::X509Sha256Digest(_) => keytype::SHA256_OF_X509,
CertifiedKey::Ed25519(_) => KeyType::ED25519_KEY,
CertifiedKey::RSASha256Digest(_) => KeyType::SHA256_OF_RSA,
CertifiedKey::X509Sha256Digest(_) => KeyType::SHA256_OF_X509,
CertifiedKey::Unrecognized(u) => u.key_type,
}
@ -150,11 +157,11 @@ impl CertifiedKey {
}
/// Try to extract a CertifiedKey from a Reader, given that we have
/// already read its type as `key_type`.
fn from_reader(key_type: u8, r: &mut Reader) -> Result<Self> {
fn from_reader(key_type: KeyType, r: &mut Reader) -> Result<Self> {
Ok(match key_type {
keytype::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
keytype::SHA256_OF_RSA => CertifiedKey::RSASha256Digest(r.extract()?),
keytype::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
KeyType::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
KeyType::SHA256_OF_RSA => CertifiedKey::RSASha256Digest(r.extract()?),
KeyType::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
_ => CertifiedKey::Unrecognized(UnrecognizedKey {
key_type,
key_digest: r.extract()?,
@ -176,16 +183,16 @@ struct UnrecognizedExt {
/// certificate.
affects_validation: bool,
/// The type of the extension
ext_type: u8,
ext_type: ExtType,
/// The body of the extension.
body: Vec<u8>,
}
impl CertExt {
/// Return the identifier code for this Extension.
pub fn get_ext_id(&self) -> u8 {
pub fn get_ext_id(&self) -> ExtType {
match self {
CertExt::SignedWithEd25519(_) => exttype::SIGNED_WITH_ED25519_KEY,
CertExt::SignedWithEd25519(_) => ExtType::SIGNED_WITH_ED25519_KEY,
CertExt::Unrecognized(u) => u.ext_type,
}
}
@ -210,7 +217,7 @@ impl Writeable for SignedWithEd25519Ext {
// body length
w.write_u16(32);
// Signed-with-ed25519-key-extension
w.write_u8(exttype::SIGNED_WITH_ED25519_KEY);
w.write_u8(ExtType::SIGNED_WITH_ED25519_KEY.into());
// flags = 0.
w.write_u8(0);
// body
@ -228,7 +235,7 @@ impl Writeable for UnrecognizedExt {
fn write_onto<B: Writer + ?Sized>(&self, w: &mut B) {
self.assert_rep_ok();
w.write_u16(self.body.len() as u16);
w.write_u8(self.ext_type);
w.write_u8(self.ext_type.into());
let flags = if self.affects_validation { 1 } else { 0 };
w.write_u8(flags);
w.write_all(&self.body[..]);
@ -238,12 +245,12 @@ impl Writeable for UnrecognizedExt {
impl Readable for CertExt {
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
let len = b.take_u16()?;
let ext_type = b.take_u8()?;
let ext_type: ExtType = b.take_u8()?.into();
let flags = b.take_u8()?;
let body = b.take(len as usize)?;
Ok(match ext_type {
exttype::SIGNED_WITH_ED25519_KEY => {
ExtType::SIGNED_WITH_ED25519_KEY => {
if body.len() != 32 {
return Err(Error::BadMessage("wrong length on Ed25519 key"));
}
@ -281,9 +288,9 @@ impl Ed25519Cert {
self.assert_rep_ok();
let mut w = Vec::new();
w.write_u8(1); // Version
w.write_u8(self.cert_type);
w.write_u8(self.cert_type.into());
w.write_u32(self.exp_hours);
w.write_u8(self.cert_key.get_key_type());
w.write_u8(self.cert_key.get_key_type().into());
w.write_all(self.cert_key.as_bytes());
for e in self.extensions.iter() {
@ -316,9 +323,9 @@ impl Ed25519Cert {
// understand those.
return Err(Error::BadMessage("Unrecognized certificate version"));
}
let cert_type = r.take_u8()?;
let cert_type = r.take_u8()?.into();
let exp_hours = r.take_u32()?;
let cert_key_type = r.take_u8()?;
let cert_key_type = r.take_u8()?.into();
let cert_key = CertifiedKey::from_reader(cert_key_type, &mut r)?;
let n_exts = r.take_u8()?;
let mut extensions = Vec::new();
@ -333,7 +340,7 @@ impl Ed25519Cert {
let keyext = extensions
.iter()
.find(|e| e.get_ext_id() == exttype::SIGNED_WITH_ED25519_KEY);
.find(|e| e.get_ext_id() == ExtType::SIGNED_WITH_ED25519_KEY);
let included_pkey = match keyext {
Some(CertExt::SignedWithEd25519(s)) => Some(&s.pk),
@ -390,10 +397,7 @@ impl Ed25519Cert {
}
/// Return the type of this certificate.
///
/// The value will be one of certtype::* if this certificate type is
/// recognized.
pub fn get_cert_type(&self) -> u8 {
pub fn get_cert_type(&self) -> CertType {
self.cert_type
}
}

View File

@ -147,7 +147,7 @@ mod rsa {
mod edcert {
use crate::{Error, Pos, Result};
use tor_cert::Ed25519Cert;
use tor_cert::{CertType, Ed25519Cert};
use tor_llcrypto::pk::ed25519;
/// An ed25519 certificate as parsed from a directory object, with
@ -179,7 +179,7 @@ mod edcert {
}
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> {
pub fn check_cert_type(self, desired_type: CertType) -> Result<Self> {
if self.0.get_cert_type() != desired_type {
return Err(Error::BadObjectVal(
self.1,

View File

@ -313,7 +313,7 @@ impl RouterDesc {
let cert: tor_cert::Ed25519Cert = cert_tok
.parse_obj::<UnvalidatedEdCert>("ED25519 CERT")?
.validate(None)?
.check_cert_type(tor_cert::certtype::IDENTITY_V_SIGNING)?
.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())
@ -423,7 +423,7 @@ impl RouterDesc {
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_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());