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:
| Type | Name | Purpose |
|---|---|---|
| 4 | Ed25519 Signing | Signs server descriptors |
| 5 | Link Auth | TLS link authentication |
| 6 | Ed25519 Auth | Ed25519 authentication |
| 8 | Short-term Signing | Short-term descriptor signing |
| 9 | Intro Point Auth | HS introduction point auth |
| 11 | Ntor Onion Key | Ntor 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_expiredbefore trusting a certificate - The signature should be verified against the signing key
- Unknown certificate types are rejected for security
- Extensions with
ExtensionFlag::AffectsValidationmust 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
Ed25519Extension- Extensions within certificatesCertType- Certificate type enumeration- cert-spec.txt - Tor specification
Fields§
§version: u8Certificate format version.
Currently only version 1 is supported. Future versions may have different structures.
cert_type: CertTypeThe parsed certificate type.
Indicates the purpose of this certificate. See CertType
for the full enumeration.
type_int: u8The 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: u8The 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
impl Ed25519Certificate
Sourcepub fn unpack(content: &[u8]) -> Result<Self, Error>
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)?;Sourcepub fn from_base64(content: &str) -> Result<Self, Error>
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();Sourcepub fn pack(&self) -> Vec<u8> ⓘ
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);Sourcepub fn to_base64(&self) -> String
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();Sourcepub fn to_base64_pem(&self) -> String
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-----"));Sourcepub fn is_expired(&self) -> bool
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);
}Sourcepub fn signing_key(&self) -> Option<&[u8]>
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 presentNone- 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
impl Clone for Ed25519Certificate
Source§fn clone(&self) -> Ed25519Certificate
fn clone(&self) -> Ed25519Certificate
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more