Ed25519Certificate

Struct Ed25519Certificate 

Source
pub struct Ed25519Certificate {
    pub version: u8,
    pub cert_type: CertType,
    pub type_int: u8,
    pub expiration: DateTime<Utc>,
    pub key_type: u8,
    pub key: [u8; 32],
    pub extensions: Vec<Ed25519Extension>,
    pub signature: [u8; 64],
}
Expand description

A version 1 Ed25519 certificate used in Tor descriptors.

Ed25519 certificates are used throughout Tor to bind Ed25519 keys to identities and validate signatures on descriptors. They are found in:

  • Server descriptors (signing key certificates)
  • Hidden service v3 descriptors (blinded key certificates)
  • Introduction point authentication

§Certificate Types

The certificate type indicates its purpose. Common types include:

TypeNamePurpose
4Ed25519 SigningSigns server descriptors
5Link AuthTLS link authentication
6Ed25519 AuthEd25519 authentication
8Short-term SigningShort-term descriptor signing
9Intro Point AuthHS introduction point auth
11Ntor Onion KeyNtor key cross-certification

§Invariants

  • Version is always 1 (only supported version)
  • Key is always exactly 32 bytes
  • Signature is always exactly 64 bytes
  • Certificate types 1, 2, 3, and 7 are reserved and rejected

§Security Considerations

  • Always verify is_expired before trusting a certificate
  • The signature should be verified against the signing key
  • Unknown certificate types are rejected for security
  • Extensions with ExtensionFlag::AffectsValidation must be understood

§Example

use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";

let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

// Check certificate properties
assert_eq!(cert.version, 1);
println!("Type: {:?}", cert.cert_type);
println!("Expires: {}", cert.expiration);

// Check if expired
if cert.is_expired() {
    println!("Certificate has expired!");
}

// Get signing key if present
if let Some(key) = cert.signing_key() {
    println!("Signing key: {} bytes", key.len());
}

§See Also

Fields§

§version: u8

Certificate format version.

Currently only version 1 is supported. Future versions may have different structures.

§cert_type: CertType

The parsed certificate type.

Indicates the purpose of this certificate. See CertType for the full enumeration.

§type_int: u8

The raw integer value of the certificate type.

Preserved for round-trip encoding and debugging.

§expiration: DateTime<Utc>

When this certificate expires.

Certificates should not be trusted after this time. Use is_expired to check validity.

§Note

The expiration is stored in the certificate as hours since Unix epoch, so the precision is limited to one hour.

§key_type: u8

The key type (always 1 for Ed25519).

This field indicates the type of key in the key field. Currently only type 1 (Ed25519) is defined.

§key: [u8; 32]

The certified Ed25519 public key.

This is the key being certified by this certificate. Its meaning depends on the certificate type.

§extensions: Vec<Ed25519Extension>

Extensions included in this certificate.

Extensions provide additional data such as the signing key. See Ed25519Extension for details.

§signature: [u8; 64]

The Ed25519 signature over the certificate body.

This signature covers all certificate data except the signature itself. It should be verified using the signing key (from an extension or provided externally).

Implementations§

Source§

impl Ed25519Certificate

Source

pub fn unpack(content: &[u8]) -> Result<Self, Error>

Parses an Ed25519 certificate from its binary representation.

This method decodes a certificate from raw bytes as they appear in descriptors after base64 decoding.

§Arguments
  • content - The raw certificate bytes
§Returns

The parsed Ed25519Certificate on success.

§Errors

Returns Error::Parse if:

  • The input is too short (minimum 104 bytes: 40 header + 64 signature)
  • The version is not 1
  • The certificate type is reserved (1, 2, 3, 7) or unknown (0)
  • The expiration timestamp is invalid
  • Extension parsing fails
  • There is unused data after parsing extensions
§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

// Typically you'd get these bytes from base64 decoding
// let cert = Ed25519Certificate::unpack(&decoded_bytes)?;
Source

pub fn from_base64(content: &str) -> Result<Self, Error>

Parses an Ed25519 certificate from a base64-encoded string.

This method handles both raw base64 and PEM-formatted certificates (with -----BEGIN ED25519 CERT----- headers).

§Arguments
  • content - The base64-encoded certificate string
§Returns

The parsed Ed25519Certificate on success.

§Errors

Returns Error::Parse if:

  • The input is empty
  • The base64 encoding is invalid
  • The decoded certificate is malformed (see unpack)
§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

// Raw base64
let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

// PEM format also works
let pem = format!(
    "-----BEGIN ED25519 CERT-----\n{}\n-----END ED25519 CERT-----",
    cert_b64
);
let cert2 = Ed25519Certificate::from_base64(&pem).unwrap();
Source

pub fn pack(&self) -> Vec<u8>

Encodes this certificate to its binary representation.

The encoded format matches the Tor specification and can be decoded with unpack.

§Returns

A byte vector containing the encoded certificate.

§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

let packed = cert.pack();
let reparsed = Ed25519Certificate::unpack(&packed).unwrap();
assert_eq!(cert, reparsed);
Source

pub fn to_base64(&self) -> String

Encodes this certificate to a base64 string.

The output is formatted with line breaks every 64 characters, suitable for embedding in descriptors.

§Returns

A base64-encoded string representation of the certificate.

§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

let encoded = cert.to_base64();
// Can be decoded back
let decoded = Ed25519Certificate::from_base64(&encoded).unwrap();
Source

pub fn to_base64_pem(&self) -> String

Encodes this certificate to a PEM-formatted string.

The output includes -----BEGIN ED25519 CERT----- and -----END ED25519 CERT----- headers.

§Returns

A PEM-formatted string representation of the certificate.

§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

let pem = cert.to_base64_pem();
assert!(pem.starts_with("-----BEGIN ED25519 CERT-----"));
assert!(pem.ends_with("-----END ED25519 CERT-----"));
Source

pub fn is_expired(&self) -> bool

Checks if this certificate has expired.

A certificate is considered expired if the current time is past the certificate’s expiration time.

§Returns

true if the certificate has expired, false otherwise.

§Security

Always check expiration before trusting a certificate. Expired certificates should not be used for validation, even if their signatures are valid.

§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

if cert.is_expired() {
    println!("Certificate expired on {}", cert.expiration);
}
Source

pub fn signing_key(&self) -> Option<&[u8]>

Extracts the signing key from this certificate’s extensions.

The signing key is the Ed25519 public key used to sign this certificate. It is typically embedded in an extension of type ExtensionType::HasSigningKey.

§Returns
  • Some(&[u8]) - A reference to the 32-byte signing key if present
  • None - If no signing key extension exists
§Security

The signing key should be used to verify the certificate’s signature. If no signing key is embedded, it must be obtained from another source (e.g., the descriptor’s master key).

§Example
use stem_rs::descriptor::certificate::Ed25519Certificate;

let cert_b64 = "AQQABhtZAaW2GoBED1IjY3A6f6GNqBEl5A83fD2Za9upGke51JGqAQAgBABn\
                prVRptIr43bWPo2fIzo3uOywfoMrryprpbm4HhCkZMaO064LP+1KNuLvlc8s\
                GG8lTjx1g4k3ELuWYgHYWU5rAia7nl4gUfBZOEfHAfKES7l3d63dBEjEX98L\
                jhdp2w4=";
let cert = Ed25519Certificate::from_base64(cert_b64).unwrap();

match cert.signing_key() {
    Some(key) => println!("Signing key: {} bytes", key.len()),
    None => println!("No embedded signing key"),
}

Trait Implementations§

Source§

impl Clone for Ed25519Certificate

Source§

fn clone(&self) -> Ed25519Certificate

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Ed25519Certificate

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Ed25519Certificate

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Ed25519Certificate

Source§

fn eq(&self, other: &Ed25519Certificate) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Ed25519Certificate

Source§

impl StructuralPartialEq for Ed25519Certificate

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.