clean up tor-cert documentation a little.
This commit is contained in:
parent
671a266e13
commit
c65c40170d
|
@ -10,5 +10,5 @@ publish = false
|
||||||
tor-llcrypto = { path="../tor-llcrypto" }
|
tor-llcrypto = { path="../tor-llcrypto" }
|
||||||
tor-bytes = { path="../tor-bytes" }
|
tor-bytes = { path="../tor-bytes" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
base64 = "*"
|
|
@ -1,8 +1,32 @@
|
||||||
//! Implementation for the Tor certificate type
|
//! Implementation for Tor certificates
|
||||||
//!
|
//!
|
||||||
//! This is the certificate type as documented as Tor's cert-spec.txt.
|
//! This is the certificate type as documented as Tor's cert-spec.txt,
|
||||||
//! There are other types of certificate as well, but they will be
|
//! where everything is signed with ed25519 keys.
|
||||||
//! implemented in other places.
|
//!
|
||||||
|
//! There are other types of certificate used by Tor as well, but they
|
||||||
|
//! will be implemented in other places.
|
||||||
|
//!
|
||||||
|
//! # Examples
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use base64::decode;
|
||||||
|
//! use tor_cert::*;
|
||||||
|
//! // Taken from a random relay on the Tor network.
|
||||||
|
//! let cert_base64 =
|
||||||
|
//! "AQQABrntAThPWJ4nFH1L77Ar+emd4GPXZTPUYzIwmR2H6Zod5TvXAQAgBAC+vzqh
|
||||||
|
//! VFO1SGATubxcrZzrsNr+8hrsdZtyGg/Dde/TqaY1FNbeMqtAPMziWOd6txzShER4
|
||||||
|
//! qc/haDk5V45Qfk6kjcKw+k7cPwyJeu+UF/azdoqcszHRnUHRXpiPzudPoA4=";
|
||||||
|
//! // Remove the whitespace, so base64 doesn't choke on it.
|
||||||
|
//! let cert_base64: String = cert_base64.split_whitespace().collect();
|
||||||
|
//! // Decode the base64.
|
||||||
|
//! let cert_bin = base64::decode(cert_base64).unwrap();
|
||||||
|
//!
|
||||||
|
//! // Decode the cert and check its signature.
|
||||||
|
//! let cert = Ed25519Cert::decode_and_check(&cert_bin, None).unwrap();
|
||||||
|
//! let signed_key = cert.get_subject_key();
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use tor_bytes::{Error, Result};
|
use tor_bytes::{Error, Result};
|
||||||
use tor_bytes::{Readable, Reader, Writeable, Writer};
|
use tor_bytes::{Readable, Reader, Writeable, Writer};
|
||||||
|
@ -32,6 +56,8 @@ pub mod certtype {
|
||||||
|
|
||||||
// 08 through 09 are for onion services.
|
// 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;
|
pub const NTOR_CC_IDENTITY: u8 = 0x0A;
|
||||||
|
|
||||||
// 0B is for onion services.
|
// 0B is for onion services.
|
||||||
|
@ -45,11 +71,11 @@ pub mod exttype {
|
||||||
pub const SIGNED_WITH_ED25519_KEY: u8 = 0x04;
|
pub const SIGNED_WITH_ED25519_KEY: u8 = 0x04;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifiers for the type of a key or object getting signed.
|
/// Identifiers for the type of key or object getting signed.
|
||||||
pub mod keytype {
|
pub mod keytype {
|
||||||
/// Identifier for an Ed25519 key.
|
/// Identifier for an Ed25519 key.
|
||||||
pub const ED25519_KEY: u8 = 0x01;
|
pub const ED25519_KEY: u8 = 0x01;
|
||||||
/// Identifies for the SHA256 of an DER-encoded RSA key.
|
/// Identifier for the SHA256 of an DER-encoded RSA key.
|
||||||
pub const SHA256_OF_RSA: u8 = 0x02;
|
pub const SHA256_OF_RSA: u8 = 0x02;
|
||||||
/// Identifies the SHA256 of an X.509 certificate.
|
/// Identifies the SHA256 of an X.509 certificate.
|
||||||
pub const SHA256_OF_X509: u8 = 0x03;
|
pub const SHA256_OF_X509: u8 = 0x03;
|
||||||
|
@ -75,15 +101,21 @@ pub struct Ed25519Cert {
|
||||||
|
|
||||||
/// One of the data types that can be certified by an Ed25519Cert.
|
/// One of the data types that can be certified by an Ed25519Cert.
|
||||||
pub enum CertifiedKey {
|
pub enum CertifiedKey {
|
||||||
|
/// An Ed25519 public key, signed directly.
|
||||||
Ed25519(ed25519::PublicKey),
|
Ed25519(ed25519::PublicKey),
|
||||||
RSADigest([u8; 32]),
|
/// The SHA256 digest of a DER-encoded RSAPublicKey
|
||||||
X509Digest([u8; 32]),
|
RSASha256Digest([u8; 32]),
|
||||||
|
/// The SHA256 digest of an X.509 certificate.
|
||||||
|
X509Sha256Digest([u8; 32]),
|
||||||
|
/// Some unrecognized key type.
|
||||||
Unrecognized(UnrecognizedKey),
|
Unrecognized(UnrecognizedKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A key whose type we didn't recognize.
|
/// A key whose type we didn't recognize.
|
||||||
pub struct UnrecognizedKey {
|
pub struct UnrecognizedKey {
|
||||||
|
/// Actual type of the key.
|
||||||
key_type: u8,
|
key_type: u8,
|
||||||
|
/// digest of the key, or the key itself.
|
||||||
key_digest: [u8; 32],
|
key_digest: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +124,8 @@ impl CertifiedKey {
|
||||||
pub fn get_key_type(&self) -> u8 {
|
pub fn get_key_type(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
CertifiedKey::Ed25519(_) => keytype::ED25519_KEY,
|
CertifiedKey::Ed25519(_) => keytype::ED25519_KEY,
|
||||||
CertifiedKey::RSADigest(_) => keytype::SHA256_OF_RSA,
|
CertifiedKey::RSASha256Digest(_) => keytype::SHA256_OF_RSA,
|
||||||
CertifiedKey::X509Digest(_) => keytype::SHA256_OF_X509,
|
CertifiedKey::X509Sha256Digest(_) => keytype::SHA256_OF_X509,
|
||||||
|
|
||||||
CertifiedKey::Unrecognized(u) => u.key_type,
|
CertifiedKey::Unrecognized(u) => u.key_type,
|
||||||
}
|
}
|
||||||
|
@ -103,8 +135,8 @@ impl CertifiedKey {
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
match self {
|
match self {
|
||||||
CertifiedKey::Ed25519(k) => k.as_bytes(),
|
CertifiedKey::Ed25519(k) => k.as_bytes(),
|
||||||
CertifiedKey::RSADigest(k) => &k[..],
|
CertifiedKey::RSASha256Digest(k) => &k[..],
|
||||||
CertifiedKey::X509Digest(k) => &k[..],
|
CertifiedKey::X509Sha256Digest(k) => &k[..],
|
||||||
CertifiedKey::Unrecognized(u) => &u.key_digest[..],
|
CertifiedKey::Unrecognized(u) => &u.key_digest[..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,8 +153,8 @@ impl CertifiedKey {
|
||||||
fn from_reader(key_type: u8, r: &mut Reader) -> Result<Self> {
|
fn from_reader(key_type: u8, r: &mut Reader) -> Result<Self> {
|
||||||
Ok(match key_type {
|
Ok(match key_type {
|
||||||
keytype::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
|
keytype::ED25519_KEY => CertifiedKey::Ed25519(r.extract()?),
|
||||||
keytype::SHA256_OF_RSA => CertifiedKey::RSADigest(r.extract()?),
|
keytype::SHA256_OF_RSA => CertifiedKey::RSASha256Digest(r.extract()?),
|
||||||
keytype::SHA256_OF_X509 => CertifiedKey::X509Digest(r.extract()?),
|
keytype::SHA256_OF_X509 => CertifiedKey::X509Sha256Digest(r.extract()?),
|
||||||
_ => CertifiedKey::Unrecognized(UnrecognizedKey {
|
_ => CertifiedKey::Unrecognized(UnrecognizedKey {
|
||||||
key_type,
|
key_type,
|
||||||
key_digest: r.extract()?,
|
key_digest: r.extract()?,
|
||||||
|
@ -132,12 +164,14 @@ impl CertifiedKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An extension in a Tor certificate.
|
/// An extension in a Tor certificate.
|
||||||
pub enum CertExt {
|
enum CertExt {
|
||||||
|
/// Indicates which Ed25519 public key signed this cert.
|
||||||
SignedWithEd25519(SignedWithEd25519Ext),
|
SignedWithEd25519(SignedWithEd25519Ext),
|
||||||
|
/// An extension whose identity we don't recognize.
|
||||||
Unrecognized(UnrecognizedExt),
|
Unrecognized(UnrecognizedExt),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UnrecognizedExt {
|
struct UnrecognizedExt {
|
||||||
/// True iff this extension must be understand in order to validate the
|
/// True iff this extension must be understand in order to validate the
|
||||||
/// certificate.
|
/// certificate.
|
||||||
affects_validation: bool,
|
affects_validation: bool,
|
||||||
|
@ -166,8 +200,8 @@ impl Writeable for CertExt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extension indicating that key that signed a given certificate.
|
/// Extension indicating that a key that signed a given certificate.
|
||||||
pub struct SignedWithEd25519Ext {
|
struct SignedWithEd25519Ext {
|
||||||
pk: ed25519::PublicKey,
|
pk: ed25519::PublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +213,7 @@ impl Writeable for SignedWithEd25519Ext {
|
||||||
w.write_u8(exttype::SIGNED_WITH_ED25519_KEY);
|
w.write_u8(exttype::SIGNED_WITH_ED25519_KEY);
|
||||||
// flags = 0.
|
// flags = 0.
|
||||||
w.write_u8(0);
|
w.write_u8(0);
|
||||||
|
// body
|
||||||
w.write_all(self.pk.as_bytes());
|
w.write_all(self.pk.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,6 +269,8 @@ impl Readable for CertExt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ed25519Cert {
|
impl Ed25519Cert {
|
||||||
|
/// Helper: Assert that there is nothing wrong with the
|
||||||
|
/// internal structure of this certificate.
|
||||||
fn assert_rep_ok(&self) {
|
fn assert_rep_ok(&self) {
|
||||||
assert!(self.extensions.len() <= std::u8::MAX as usize);
|
assert!(self.extensions.len() <= std::u8::MAX as usize);
|
||||||
}
|
}
|
||||||
|
@ -330,6 +367,7 @@ impl Ed25519Cert {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the time at which this certificate becomes expired
|
||||||
pub fn get_expiry(&self) -> std::time::SystemTime {
|
pub fn get_expiry(&self) -> std::time::SystemTime {
|
||||||
let d = std::time::Duration::new((self.exp_hours as u64) * 3600, 0);
|
let d = std::time::Duration::new((self.exp_hours as u64) * 3600, 0);
|
||||||
std::time::SystemTime::UNIX_EPOCH + d
|
std::time::SystemTime::UNIX_EPOCH + d
|
||||||
|
@ -351,8 +389,10 @@ impl Ed25519Cert {
|
||||||
&self.signed_with
|
&self.signed_with
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the type of this certificate (as one of certtype::* if this
|
/// Return the type of this certificate.
|
||||||
/// certificate type is recognized).
|
///
|
||||||
|
/// 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) -> u8 {
|
||||||
self.cert_type
|
self.cert_type
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue