feat: license validation commands + entitlements system (#46) #56

Merged
maximus merged 3 commits from issue-46-license-commands-entitlements into main 2026-04-09 19:35:33 +00:00
Showing only changes of commit 2e9df1c0b9 - Show all commits

View file

@ -279,10 +279,16 @@ mod tests {
use ed25519_dalek::SigningKey; use ed25519_dalek::SigningKey;
use jsonwebtoken::{encode, EncodingKey, Header}; use jsonwebtoken::{encode, EncodingKey, Header};
// === Manual DER encoders for Ed25519 keys ================================================= // === Manual DER encoder for the Ed25519 private key =======================================
// We avoid the `pem` feature on `ed25519-dalek` because the `LineEnding` re-export path // We avoid the `pem` feature on `ed25519-dalek` because the `LineEnding` re-export path
// varies across `pkcs8`/`spki`/`der` versions. The Ed25519 PKCS#8 v1 byte layout is fixed // varies across `pkcs8`/`spki`/`der` versions. The Ed25519 PKCS#8 v1 byte layout is fixed
// and trivial: prefix + 32-byte raw key. // and trivial: 16-byte prefix + 32-byte raw seed.
//
// Note the asymmetry in jsonwebtoken's API:
// - `EncodingKey::from_ed_der` expects a PKCS#8-wrapped private key (passed to ring's
// `Ed25519KeyPair::from_pkcs8`).
// - `DecodingKey::from_ed_der` expects the *raw* 32-byte public key (passed to ring's
// `UnparsedPublicKey::new` which takes raw bytes, not a SubjectPublicKeyInfo).
/// Wrap a 32-byte Ed25519 seed in a PKCS#8 v1 PrivateKeyInfo DER blob. /// Wrap a 32-byte Ed25519 seed in a PKCS#8 v1 PrivateKeyInfo DER blob.
fn ed25519_pkcs8_private_der(seed: &[u8; 32]) -> Vec<u8> { fn ed25519_pkcs8_private_der(seed: &[u8; 32]) -> Vec<u8> {
@ -303,28 +309,14 @@ mod tests {
der der
} }
/// Wrap a 32-byte Ed25519 public key in a SubjectPublicKeyInfo DER blob.
fn ed25519_spki_public_der(pubkey: &[u8; 32]) -> Vec<u8> {
// SEQUENCE(42) {
// SEQUENCE(5) { OID(3) 1.3.101.112 }
// BIT STRING(33) { 00 <32 bytes> }
// }
let mut der = vec![
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
];
der.extend_from_slice(pubkey);
der
}
/// Build a deterministic test keypair so signed tokens are reproducible across runs. /// Build a deterministic test keypair so signed tokens are reproducible across runs.
/// Returns (private_der, decoding_key_for_verification).
fn test_keys(seed: [u8; 32]) -> (EncodingKey, DecodingKey) { fn test_keys(seed: [u8; 32]) -> (EncodingKey, DecodingKey) {
let signing_key = SigningKey::from_bytes(&seed); let signing_key = SigningKey::from_bytes(&seed);
let pubkey_bytes = signing_key.verifying_key().to_bytes(); let pubkey_bytes = signing_key.verifying_key().to_bytes();
let priv_der = ed25519_pkcs8_private_der(&seed); let priv_der = ed25519_pkcs8_private_der(&seed);
let pub_der = ed25519_spki_public_der(&pubkey_bytes);
let encoding_key = EncodingKey::from_ed_der(&priv_der); let encoding_key = EncodingKey::from_ed_der(&priv_der);
let decoding_key = DecodingKey::from_ed_der(&pub_der); // Raw 32-byte public key (NOT SubjectPublicKeyInfo) — see note above.
let decoding_key = DecodingKey::from_ed_der(&pubkey_bytes);
(encoding_key, decoding_key) (encoding_key, decoding_key)
} }