# Keys
## Algorithm identification
`identify_signature_algorithm` and `identify_public_key_algorithm` use integer
dispatch on OID components. They never allocate and return `&'static str`.
```rust,ignore
use synta::ObjectIdentifier;
use synta_certificate::{oids, names, identify_signature_algorithm, identify_public_key_algorithm};
let oid = ObjectIdentifier::new(oids::SHA256_WITH_RSA).unwrap();
assert_eq!(identify_signature_algorithm(&oid), names::SHA256_WITH_RSA);
let oid = ObjectIdentifier::new(oids::ML_DSA_44).unwrap();
assert_eq!(identify_signature_algorithm(&oid), names::ML_DSA_44);
let oid = ObjectIdentifier::new(oids::ML_KEM_768).unwrap();
assert_eq!(identify_public_key_algorithm(&oid), Some(names::ML_KEM_768));
```
## Supported signature algorithms
| RSA (PKCS #1) | 1.2.840.113549.1.1.* | RFC 3279 |
| ECDSA | 1.2.840.10045.4.* | RFC 5480 |
| EdDSA (Ed25519) | 1.3.101.112 | RFC 8410 |
| EdDSA (Ed448) | 1.3.101.113 | RFC 8410 |
| ML-DSA-44/65/87 | 2.16.840.1.101.3.4.3.17–19 | FIPS 204 |
| DSA | 1.2.840.10040.4.* | FIPS 186 |
## Supported public key algorithms
| RSA | RFC 3279 |
| ECDSA (P-256, P-384, P-521) | RFC 5480 |
| EdDSA (Ed25519, Ed448) | RFC 8410 |
| ML-DSA (44, 65, 87) | FIPS 204 |
| ML-KEM (512, 768, 1024) | FIPS 203 |
| DSA | FIPS 186 |
## Public key decoding
`decode_public_key_info` dispatches on the algorithm OID and returns a
`PublicKeyInfo` enum with algorithm-specific fields:
```rust,ignore
use synta_certificate::{decode_public_key_info, PublicKeyInfo};
let spki = &cert.tbs_certificate.subject_public_key_info;
let info = decode_public_key_info(
&spki.algorithm.algorithm,
spki.algorithm.parameters.as_ref(),
spki.subject_public_key.as_bytes(),
spki.subject_public_key.bit_len(),
);
match info {
PublicKeyInfo::Rsa { modulus, exponent, bit_count } => {
println!("RSA-{}, exponent={}", bit_count, exponent);
}
PublicKeyInfo::Ec { bit_count, curve_nist_name, .. } => {
println!("EC-{} ({})", bit_count, curve_nist_name.unwrap_or("?"));
}
PublicKeyInfo::MlDsa { security_level, public_key_size } => {
println!("ML-DSA-{} ({} bytes)", security_level, public_key_size);
}
PublicKeyInfo::Unknown { alg_name, .. } => {
println!("Unknown: {}", alg_name);
}
}
```
## PKCS#8 private keys
The `pkcs8_types` module provides `OneAsymmetricKey<'a>` (RFC 5958) and a
`PrivateKeyInfo<'a>` alias:
```rust,ignore
use synta::{Decoder, Encoding};
use synta_certificate::pkcs8_types::OneAsymmetricKey;
let der = std::fs::read("private.key")?;
let mut dec = Decoder::new(&der, Encoding::Der);
let key: OneAsymmetricKey = dec.decode()?;
println!("Version: {:?}", key.version);
println!("Algorithm: {:?}", key.private_key_algorithm.algorithm);
```
## RFC 3279 algorithm parameters
The `pkixalgs_types` module provides DSA/DH domain parameter types, ECDSA
signature value types, and EC parameter types:
```rust
use synta::{Decoder, Encoding};
use synta_certificate::pkixalgs_types::{DssParms, EcdsaSigValue, ECParameters};
// DSA domain parameters
let parms = DssParms {
p: Integer::from(23u64),
q: Integer::from(11u64),
g: Integer::from(5u64),
};
// ECDSA signature value (r, s)
let sig = EcdsaSigValue {
r: Integer::from(42u64),
s: Integer::from(17u64),
};
// EC named curve (P-256 = 1.2.840.10045.3.1.7)
let curve_oid = synta::ObjectIdentifier::new(&[1, 2, 840, 10045, 3, 1, 7]).unwrap();
let params = ECParameters::NamedCurve(curve_oid);
```
## Crypto backends: NSS and OpenSSL
`synta-certificate` supports two pluggable crypto backends selected at compile time:
| `openssl` | yes | OpenSSL bindings via the `openssl` crate |
| `nss` | no | Mozilla NSS via the `nss-sys` crate |
When both features are compiled in, **NSS takes priority** in all dispatch points.
To select NSS as the sole backend:
```toml
[dependencies]
synta-certificate = { version = "0.1", default-features = false, features = ["std", "derive", "nss"] }
```
### Backend-agnostic key abstractions
The recommended approach to key generation and signing never names a backend type:
```rust,ignore
use synta_certificate::{PrivateKeyBuilder, CertificateBuilder};
// Generate a P-256 key (delegates to OpenSSL or NSS depending on active features)
let key = PrivateKeyBuilder::ec("P-256").generate()?;
// Public key as DER-encoded SubjectPublicKeyInfo — use it with CertificateBuilder
let spki_der = key.public_key_spki_der()?;
// Create a signer; "sha256" selects the hash (ignored for EdDSA)
let signer = key.as_signer("sha256");
// Pass the signer directly to CertificateBuilder::sign
let cert_der = CertificateBuilder::new()
/* … set fields … */
.sign(signer.as_ref())?;
```
Other key algorithms:
```rust,ignore
let rsa_key = PrivateKeyBuilder::rsa(3072).generate()?;
let ed_key = PrivateKeyBuilder::ed25519().generate()?;
let pqc_key = PrivateKeyBuilder::ml_dsa("ML-DSA-65").generate()?; // OpenSSL 3.5+
```
`BackendPrivateKey` can be used when you need to load, store, or serialise PKCS#8 bytes:
```rust,ignore
use synta_certificate::BackendPrivateKey;
// Load from unencrypted PKCS#8 DER (validates the key on load)
let key = BackendPrivateKey::from_der(&pkcs8_der)?;
// Load from PEM, optionally password-protected
let key = BackendPrivateKey::from_pem(pem_bytes, None)?;
let key = BackendPrivateKey::from_pem(pem_bytes, Some(b"passphrase"))?;
```
`BackendPrivateKey` also implements the `PrivateKey` trait, so `key.as_signer("sha256")`
and `key.public_key_spki_der()` work just like with the boxed trait object from
`PrivateKeyBuilder::generate`.
### Backend-dispatched factory functions
`default_signature_verifier` and `default_key_id_hasher` return trait objects backed by
whichever feature is active:
```rust,ignore
use synta_certificate::{default_signature_verifier, default_key_id_hasher};
let verifier = default_signature_verifier(); // Box<dyn ErasedSignatureVerifier>
let hasher = default_key_id_hasher(); // Box<dyn ErasedKeyIdHasher>
```
### BackendPublicKey — verify any X.509 signature
`BackendPublicKey::verify_signature` verifies an X.509 signature using the full
`AlgorithmIdentifier` DER from the certificate, routing to NSS when enabled:
```rust,ignore
use synta_certificate::BackendPublicKey;
// spki_der: DER-encoded SubjectPublicKeyInfo (Vec<u8> or &[u8])
let pub_key = BackendPublicKey::from_spki_der(spki_der);
pub_key.verify_signature(tbs_der, sig_alg_der, signature)?;
```
- `tbs_der` — DER bytes of `TBSCertificate` (the bytes that were signed).
- `sig_alg_der` — DER bytes of the outer `AlgorithmIdentifier` SEQUENCE.
- `signature` — raw signature bytes (BIT STRING value, unused-bits byte stripped).
Returns `Ok(())` on success, `Err(PrivateKeyError)` on failure or unsupported algorithm.
`BackendPublicKey` also exposes key-introspection methods (all require the `openssl`
feature): `from_pem`, `from_der`, `from_rsa_components`, `from_ec_components`,
`key_type()`, `key_bit_size()`, `rsa_modulus()`, `rsa_public_exponent()`,
`ec_curve_name()`, `ec_affine_coordinates()`, `rsa_oaep_encrypt()`, `verify_message()`.
### NSS backend types (`nss` feature)
| `NssSignatureVerifier` | Verifies signatures via `VFY_VerifyDataWithAlgorithmID`; supports RSA PKCS#1 / RSA-PSS / ECDSA / EdDSA / ML-DSA |
| `NssVerifierError` | Error type for `NssSignatureVerifier` |
| `NssSigner` | Signs TBS blobs from a PKCS#8 private key imported into the NSS in-memory softokn slot |
| `NssSignerError` | Error type for `NssSigner` |
| `NssKeyIdHasher` | SHA-1/256/384/512 via `PK11_HashBuf` for SKI/AKI extension encoding |
| `NssKeyIdHasherError` | Error type for `NssKeyIdHasher` |
### OpenSSL backend types (`openssl` feature)
| `OpensslPrivateKey` | OpenSSL-backed private key; implements `PrivateKey` |
| `OpensslCertificateSigner` | Implements `CertificateSigner` around an OpenSSL `PKey<Private>` |
| `OpensslCertificateSignerError` | Error type for `OpensslCertificateSigner` |
| `OpensslSignatureVerifier` | Verifies X.509 signatures via OpenSSL EVP |
| `OpensslVerifierError` | Error type for `OpensslSignatureVerifier` |
| `OpensslKeyIdHasher` | SHA-1/256/384/512 hashing for SKI/AKI encoding |
| `OpensslKeyIdHasherError` | Error type for `OpensslKeyIdHasher` |
## PKCS#9 OID constants
9 attribute OIDs from RFC 2985, RFC 5652, RFC 2986, and RFC 7292 are exposed in
`oids`:
| `PKCS9_EMAIL_ADDRESS` | 9.1 |
| `PKCS9_UNSTRUCTURED_NAME` | 9.2 |
| `PKCS9_CONTENT_TYPE` | 9.3 |
| `PKCS9_MESSAGE_DIGEST` | 9.4 |
| `PKCS9_SIGNING_TIME` | 9.5 |
| `PKCS9_COUNTERSIGNATURE` | 9.6 |
| `PKCS9_CHALLENGE_PASSWORD` | 9.7 |
| `PKCS9_EXTENSION_REQUEST` | 9.14 |
| `PKCS9_FRIENDLY_NAME` | 9.20 |
| `PKCS9_LOCAL_KEY_ID` | 9.21 |