-
Notifications
You must be signed in to change notification settings - Fork 0
Add ES256 and PS256 signing algorithm support #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 12 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
3d45e63
Add ES256 and PS256 signing algorithm support
zshenker 0a4562a
Add example that mints sample ES256/PS256 tokens
zshenker db41b80
Address PR review: fix MSRV, harden tests, warn on demo keys
zshenker 7b85884
Clarify to_bytes tagging comment for the untagged (no-algorithm) case
zshenker 158bb17
Address review: 0.3.0 breaking release + tighten tamper test
zshenker 43cc2ab
Add CHANGELOG documenting 0.3.0 and prior releases
zshenker 079409e
Fix COSE protected-header interop; centralize algorithm→structure map…
zshenker 978ea48
Preserve original payload bytes in to_bytes()
zshenker 424d67d
Update obsoleted RFC 8152 reference to RFC 9053
zshenker d814b78
Pin claims in PS256 randomization test so salt is the only entropy
zshenker bdae217
Assert PSS salt randomization at the full-token byte level
zshenker ac8fa56
Fix verification regression for lossy-but-valid claim payloads
zshenker f54f710
Enforce canonical low-S ECDSA signatures for ES256
zshenker 5b04be7
Enforce 2048-bit RSA floor for PS256; centralize COSE tag mapping
zshenker af2542d
Reject to_bytes() on a token with no algorithm
zshenker 759948d
Extract RSA key-size check; drop test-only public method
zshenker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to this project are documented in this file. | ||
|
|
||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), | ||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
|
||
| ## [0.3.0] - Unreleased | ||
|
|
||
| ### Added | ||
|
|
||
| - **ES256** (ECDSA using the P-256 curve and SHA-256) signing and verification | ||
| support, producing/consuming `COSE_Sign1` structures. | ||
| - **PS256** (RSASSA-PSS using SHA-256 and MGF1 with SHA-256) signing and | ||
| verification support, producing/consuming `COSE_Sign1` structures. | ||
| - `Algorithm::Es256` and `Algorithm::Ps256` variants, plus their COSE algorithm | ||
| identifiers (`-7` and `-37`). | ||
| - `Error::InvalidKey` for malformed DER key material. | ||
| - `examples/asymmetric_signing.rs` and `examples/sample_es256_ps256_tokens.rs` | ||
| demonstrating the new asymmetric algorithms and key formats. | ||
|
|
||
| ### Changed | ||
|
|
||
| - **BREAKING:** `Algorithm` and `Error` are now `#[non_exhaustive]`. Downstream | ||
| `match` expressions over either enum must include a wildcard arm. This is a | ||
| one-time break that allows future variants (additional algorithms or error | ||
| cases) to be added without further breakage. | ||
| - **BREAKING:** Minimum supported Rust version (MSRV) raised to `1.88.0`, | ||
| required by the asymmetric crypto dependencies. | ||
| - Tokens are tagged according to their algorithm: HMAC (MAC) algorithms use | ||
| `COSE_Mac0` (tag 17) while asymmetric signature algorithms use `COSE_Sign1` | ||
| (tag 18). `Token::from_bytes` accepts both tagged and untagged input. | ||
|
|
||
| ## [0.2.7] - 2025-11-05 | ||
|
|
||
| ### Added | ||
|
|
||
| - **CATTPRINT** (TLS Fingerprint) claim support, including verification of | ||
| fingerprint type and value. | ||
| - `FingerprintType` enum representing the supported TLS fingerprint types. | ||
|
|
||
| ### Changed | ||
|
|
||
| - TLS fingerprint values are matched case-insensitively (compared in lowercase). | ||
| - Updated dependencies. | ||
|
|
||
| ### Fixed | ||
|
|
||
| - Corrected error messages and comments around fingerprint matching. | ||
| - Handle signed integer CBOR types when decoding claims. | ||
|
|
||
| ## [0.2.6] - 2025-10-30 | ||
|
|
||
| ### Added | ||
|
|
||
| - **CATU** URI component matching for `FILENAME`, `STEM`, and `PARENT_PATH`. | ||
| - Additional tests and documentation for CATU URI components. | ||
| - GitHub CI workflow. | ||
|
|
||
| ### Changed | ||
|
|
||
| - Updated dependencies. | ||
|
|
||
| [0.3.0]: https://github.com/fastly/rust-cat/compare/0.2.7...HEAD | ||
| [0.2.7]: https://github.com/fastly/rust-cat/compare/0.2.6...0.2.7 | ||
| [0.2.6]: https://github.com/fastly/rust-cat/releases/tag/0.2.6 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| //! Example: signing and verifying tokens with the asymmetric ES256 and PS256 | ||
| //! algorithms. | ||
| //! | ||
| //! Unlike HMAC (HS256), these algorithms use a key pair: the token is signed | ||
| //! with a private key and verified with the corresponding public key, using the | ||
| //! COSE_Sign1 structure. | ||
| //! | ||
| //! Keys are interpreted as DER: | ||
| //! - signing key: PKCS#8 DER-encoded private key | ||
| //! - verifying key: SPKI DER-encoded public key | ||
| //! | ||
| //! The keys below were generated once with OpenSSL and embedded as base64 so the | ||
| //! example is self-contained: | ||
| //! | ||
| //! ES256 (P-256): | ||
| //! openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out es.pem | ||
| //! openssl pkcs8 -topk8 -nocrypt -in es.pem -outform DER # private (PKCS#8) | ||
| //! openssl pkey -in es.pem -pubout -outform DER # public (SPKI) | ||
| //! | ||
| //! PS256 (RSA-2048): | ||
| //! openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -outform DER \ | ||
| //! | openssl pkcs8 -topk8 -nocrypt -inform DER -outform DER # private (PKCS#8) | ||
| //! openssl pkey -inform DER -in priv.der -pubout -outform DER # public (SPKI) | ||
|
|
||
| use common_access_token::{ | ||
| current_timestamp, Algorithm, KeyId, RegisteredClaims, Token, TokenBuilder, VerificationOptions, | ||
| }; | ||
| use ct_codecs::{Base64, Decoder}; | ||
|
|
||
| // ⚠️ DEMO KEYS — DO NOT USE IN PRODUCTION. | ||
| // These private keys are committed to a public repository and are therefore | ||
| // publicly known. They exist only so this example is self-contained. Generate | ||
| // your own key pair (see the OpenSSL commands above) for any real use. | ||
| const ES256_PRIVATE_KEY_B64: &str = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7BOlgwBOMKscTUCaG3RmlSCgUznDdxMn+9Pvoqp4pUOhRANCAARWMcvR3DnF1U15IvgcOyAxr3pJPfOHcF7ESuY+H+ya3LCH03PC1d99/XgN1ldF+wmMxVhY0w9iop10N6tNZDTg"; | ||
| const ES256_PUBLIC_KEY_B64: &str = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVjHL0dw5xdVNeSL4HDsgMa96ST3zh3BexErmPh/smtywh9NzwtXfff14DdZXRfsJjMVYWNMPYqKddDerTWQ04A=="; | ||
|
|
||
| const PS256_PRIVATE_KEY_B64: &str = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCHjA5iauwvo2sRB529iV1c+p+WuGFzk5EUGFFLYoIHxAwo/rSmZ2/D00epwb4WzOxA4c8+1QA+0rZIN35Fti9Wiunt0b1DgC0tuSglNzpEE5gjhTDcAWZOBPOCMt9pKEuuQC4eqBRxPoG5Y14dVi46/aQOQSqU5I0T3cbeLliTzjXkrvdqySFXMGpM9/I469SZRxZbDgB8wUcB2nTIuwOokjN/Vp+BpMM5QmR66J6aFNi8LqCmQv3grUI1kM1fqrC3az/YcyXcDvjinagyXsGYgW2ZpXIf2760UXv/bASAOO01sgI8zxbIDdG6Vd+7iPhr4b/v6QIj6rpuURFfns2LAgMBAAECggEAH9CdXbdYCZRzYHNnsGGqEtVWmQNdCEo2Lr/IcQfFmnoHGqYyE67Kmm2gb/VkHyjpOQ9nXAmVvakqlMfFsSoicU84uhPVNx9CO22uwRF18R2iQ5ATGEiR0TUzTLeRHbcSEGvLB3IPHkd8Hl327K7aOglntNrR2lHM1UFkWKkLLGHObPoLBSTQLjX5JkvtpUuBgnPVlfBUc5al9+CH+m/SiC4BvVWo4hiHEKCQgMIQ/Dh8UtS9Vk91FIizqKpqBXE6+PNmAnn9ZwRjZoRNBSLn0paAyiEXXdr5rV8zeYU0ktY40J9qWEFOJmTYII4pUK1U8tukrQ0w4LUm17f8zMkufQKBgQC7MGcSrbFWVjlEwA760sG6NKOZb5sL+2etIVAJyfSoGrwr8H4aQA1WFP+pmmlCWsLZj8qfTYSyocwfT/p9aY9Na7ftyks+q1QSsDF+D7frgxmITJeCSwiPa7jnOTrmReqAEOyPn8IlytHIhJbaPxzDxPf572QIAIBgsWhdygn21QKBgQC5X9agS0u2Joypz36ZIilbgbtgmSvFAE/22U0il+3GgXQbjmxPCip1UZm1cBgmLhq12bxU1xYxJpGVPWhEsmkIrOkEfNf/RYlSvVLzbuZLQxeB1g5FDrFb1EbaegrFznv/rFonyXMeRyJ7PHtDttfN5jxNTxTiV3BQ4uobgsai3wKBgFEiW6q26mSXnt7zuApzi1CgPEDnJPb+kyNxivWTOZ4baHBLHv1VwfILy/zBVtpR6J7QOmzt9pROmOEBk3sEY/6Ur/Y7dn3FWP14rRsMyRUlj82KFSl+SEmR0WU3YxYoO8oii8Z84nPrAx68iX4zWM5p82m7n0nwnbRLcQcl6Ue5AoGACjVN42viEnjS/DLx/MrVzjU5tVsZ/vJCdQyIY+RL8seENlREgKHFrso8lbJDki6tx9/isCVcEn7WO4qzKD1O7WxgNKAPYP5aTpUgcUllIzXhoIPCK2lguPbapANefoAdcfnyyQgd78fpDTJKc3MpNSx9m6BEPSalh77HN5afC68CgYBSHR2vz1GuUzHSgU+3xKqGSc+jlroetJ1dC5913Z+9eawW7QrRfmSod+JfEiJSw8eS+5/rGYjKihMtNPyqzadRvZtp0QGZrrm1k1/vqqeeH5Uq6AgH/2Djql4tUvC3gmgpHjY7RyPDv6v+u+L9C6MP0Nu5vVfQwpAmX9bsjn/Tjw=="; | ||
| const PS256_PUBLIC_KEY_B64: &str = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh4wOYmrsL6NrEQedvYldXPqflrhhc5ORFBhRS2KCB8QMKP60pmdvw9NHqcG+FszsQOHPPtUAPtK2SDd+RbYvVorp7dG9Q4AtLbkoJTc6RBOYI4Uw3AFmTgTzgjLfaShLrkAuHqgUcT6BuWNeHVYuOv2kDkEqlOSNE93G3i5Yk8415K73askhVzBqTPfyOOvUmUcWWw4AfMFHAdp0yLsDqJIzf1afgaTDOUJkeuiemhTYvC6gpkL94K1CNZDNX6qwt2s/2HMl3A744p2oMl7BmIFtmaVyH9u+tFF7/2wEgDjtNbICPM8WyA3RulXfu4j4a+G/7+kCI+q6blERX57NiwIDAQAB"; | ||
|
Comment on lines
+40
to
+44
|
||
|
|
||
| fn main() { | ||
| demo( | ||
| "ES256 (ECDSA P-256 + SHA-256)", | ||
| Algorithm::Es256, | ||
| ES256_PRIVATE_KEY_B64, | ||
| ES256_PUBLIC_KEY_B64, | ||
| "ec-key-1", | ||
| ); | ||
|
|
||
| demo( | ||
| "PS256 (RSASSA-PSS + SHA-256)", | ||
| Algorithm::Ps256, | ||
| PS256_PRIVATE_KEY_B64, | ||
| PS256_PUBLIC_KEY_B64, | ||
| "rsa-key-1", | ||
| ); | ||
| } | ||
|
|
||
| fn demo(name: &str, alg: Algorithm, private_key_b64: &str, public_key_b64: &str, kid: &str) { | ||
| let private_key = Base64::decode_to_vec(private_key_b64, None).expect("valid private key"); | ||
| let public_key = Base64::decode_to_vec(public_key_b64, None).expect("valid public key"); | ||
|
|
||
| let now = current_timestamp(); | ||
| let token = TokenBuilder::new() | ||
| .algorithm(alg) | ||
| .protected_key_id(KeyId::string(kid)) | ||
| .registered_claims( | ||
| RegisteredClaims::new() | ||
| .with_issuer("example-issuer") | ||
| .with_subject("example-subject") | ||
| .with_audience("example-audience") | ||
| .with_expiration(now + 3600) | ||
| .with_not_before(now) | ||
| .with_issued_at(now), | ||
| ) | ||
| .custom_string(100, "custom-string-value") | ||
| .sign(&private_key) | ||
| .expect("Failed to sign token"); | ||
|
|
||
| let token_bytes = token.to_bytes().expect("Failed to encode token"); | ||
| println!( | ||
| "{name}: signed token is {} bytes ({}-byte signature)", | ||
| token_bytes.len(), | ||
| token.signature.len() | ||
| ); | ||
|
|
||
| // The verifier only needs the public key. | ||
| let decoded = Token::from_bytes(&token_bytes).expect("Failed to decode token"); | ||
| decoded | ||
| .verify(&public_key) | ||
| .expect("Failed to verify signature"); | ||
|
|
||
| let options = VerificationOptions::new() | ||
| .verify_exp(true) | ||
| .verify_nbf(true) | ||
| .expected_issuer("example-issuer") | ||
| .expected_audience("example-audience"); | ||
| decoded | ||
| .verify_claims(&options) | ||
| .expect("Failed to verify claims"); | ||
|
|
||
| println!("{name}: signature and claims verified successfully\n"); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| //! Mint sample ES256 and PS256 tokens with a ~10-year expiration and print | ||
| //! them in hex and base64url. | ||
| //! Run with: `cargo run --example sample_es256_ps256_tokens`. | ||
| //! | ||
| //! The key pairs are the same ones used by the test suite (PKCS#8 DER private | ||
| //! keys, SPKI DER public keys, base64-encoded here so the example is | ||
| //! self-contained). The public keys are printed so the tokens can be verified | ||
| //! elsewhere. | ||
|
|
||
| use common_access_token::{ | ||
| current_timestamp, Algorithm, KeyId, RegisteredClaims, Token, TokenBuilder, VerificationOptions, | ||
| }; | ||
| use ct_codecs::{Base64, Base64UrlSafeNoPadding, Decoder, Encoder, Hex}; | ||
|
|
||
| // ⚠️ DEMO KEYS — DO NOT USE IN PRODUCTION. | ||
| // These private keys are committed to a public repository (they are the same | ||
| // keys used by the test suite) and are therefore publicly known. They exist | ||
| // only so this example is self-contained. Generate your own key pair for any | ||
| // real use. | ||
| const ES256_PRIVATE_KEY_B64: &str = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7BOlgwBOMKscTUCaG3RmlSCgUznDdxMn+9Pvoqp4pUOhRANCAARWMcvR3DnF1U15IvgcOyAxr3pJPfOHcF7ESuY+H+ya3LCH03PC1d99/XgN1ldF+wmMxVhY0w9iop10N6tNZDTg"; | ||
| const ES256_PUBLIC_KEY_B64: &str = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVjHL0dw5xdVNeSL4HDsgMa96ST3zh3BexErmPh/smtywh9NzwtXfff14DdZXRfsJjMVYWNMPYqKddDerTWQ04A=="; | ||
|
|
||
| const PS256_PRIVATE_KEY_B64: &str = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCHjA5iauwvo2sRB529iV1c+p+WuGFzk5EUGFFLYoIHxAwo/rSmZ2/D00epwb4WzOxA4c8+1QA+0rZIN35Fti9Wiunt0b1DgC0tuSglNzpEE5gjhTDcAWZOBPOCMt9pKEuuQC4eqBRxPoG5Y14dVi46/aQOQSqU5I0T3cbeLliTzjXkrvdqySFXMGpM9/I469SZRxZbDgB8wUcB2nTIuwOokjN/Vp+BpMM5QmR66J6aFNi8LqCmQv3grUI1kM1fqrC3az/YcyXcDvjinagyXsGYgW2ZpXIf2760UXv/bASAOO01sgI8zxbIDdG6Vd+7iPhr4b/v6QIj6rpuURFfns2LAgMBAAECggEAH9CdXbdYCZRzYHNnsGGqEtVWmQNdCEo2Lr/IcQfFmnoHGqYyE67Kmm2gb/VkHyjpOQ9nXAmVvakqlMfFsSoicU84uhPVNx9CO22uwRF18R2iQ5ATGEiR0TUzTLeRHbcSEGvLB3IPHkd8Hl327K7aOglntNrR2lHM1UFkWKkLLGHObPoLBSTQLjX5JkvtpUuBgnPVlfBUc5al9+CH+m/SiC4BvVWo4hiHEKCQgMIQ/Dh8UtS9Vk91FIizqKpqBXE6+PNmAnn9ZwRjZoRNBSLn0paAyiEXXdr5rV8zeYU0ktY40J9qWEFOJmTYII4pUK1U8tukrQ0w4LUm17f8zMkufQKBgQC7MGcSrbFWVjlEwA760sG6NKOZb5sL+2etIVAJyfSoGrwr8H4aQA1WFP+pmmlCWsLZj8qfTYSyocwfT/p9aY9Na7ftyks+q1QSsDF+D7frgxmITJeCSwiPa7jnOTrmReqAEOyPn8IlytHIhJbaPxzDxPf572QIAIBgsWhdygn21QKBgQC5X9agS0u2Joypz36ZIilbgbtgmSvFAE/22U0il+3GgXQbjmxPCip1UZm1cBgmLhq12bxU1xYxJpGVPWhEsmkIrOkEfNf/RYlSvVLzbuZLQxeB1g5FDrFb1EbaegrFznv/rFonyXMeRyJ7PHtDttfN5jxNTxTiV3BQ4uobgsai3wKBgFEiW6q26mSXnt7zuApzi1CgPEDnJPb+kyNxivWTOZ4baHBLHv1VwfILy/zBVtpR6J7QOmzt9pROmOEBk3sEY/6Ur/Y7dn3FWP14rRsMyRUlj82KFSl+SEmR0WU3YxYoO8oii8Z84nPrAx68iX4zWM5p82m7n0nwnbRLcQcl6Ue5AoGACjVN42viEnjS/DLx/MrVzjU5tVsZ/vJCdQyIY+RL8seENlREgKHFrso8lbJDki6tx9/isCVcEn7WO4qzKD1O7WxgNKAPYP5aTpUgcUllIzXhoIPCK2lguPbapANefoAdcfnyyQgd78fpDTJKc3MpNSx9m6BEPSalh77HN5afC68CgYBSHR2vz1GuUzHSgU+3xKqGSc+jlroetJ1dC5913Z+9eawW7QrRfmSod+JfEiJSw8eS+5/rGYjKihMtNPyqzadRvZtp0QGZrrm1k1/vqqeeH5Uq6AgH/2Djql4tUvC3gmgpHjY7RyPDv6v+u+L9C6MP0Nu5vVfQwpAmX9bsjn/Tjw=="; | ||
| const PS256_PUBLIC_KEY_B64: &str = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh4wOYmrsL6NrEQedvYldXPqflrhhc5ORFBhRS2KCB8QMKP60pmdvw9NHqcG+FszsQOHPPtUAPtK2SDd+RbYvVorp7dG9Q4AtLbkoJTc6RBOYI4Uw3AFmTgTzgjLfaShLrkAuHqgUcT6BuWNeHVYuOv2kDkEqlOSNE93G3i5Yk8415K73askhVzBqTPfyOOvUmUcWWw4AfMFHAdp0yLsDqJIzf1afgaTDOUJkeuiemhTYvC6gpkL94K1CNZDNX6qwt2s/2HMl3A744p2oMl7BmIFtmaVyH9u+tFF7/2wEgDjtNbICPM8WyA3RulXfu4j4a+G/7+kCI+q6blERX57NiwIDAQAB"; | ||
|
Comment on lines
+26
to
+30
|
||
|
|
||
| // ~10 years in seconds (10 * 365.25 days). | ||
| const TEN_YEARS_SECS: u64 = 315_576_000; | ||
|
|
||
| fn main() { | ||
| let now = current_timestamp(); | ||
| let exp = now + TEN_YEARS_SECS; | ||
| println!("issued_at (iat): {now}"); | ||
| println!("expiration (exp): {exp} (~10 years from now)\n"); | ||
|
|
||
| mint( | ||
| "ES256 (ECDSA P-256 + SHA-256)", | ||
| Algorithm::Es256, | ||
| ES256_PRIVATE_KEY_B64, | ||
| ES256_PUBLIC_KEY_B64, | ||
| "es256-sample-key", | ||
| now, | ||
| exp, | ||
| ); | ||
|
|
||
| mint( | ||
| "PS256 (RSASSA-PSS + SHA-256)", | ||
| Algorithm::Ps256, | ||
| PS256_PRIVATE_KEY_B64, | ||
| PS256_PUBLIC_KEY_B64, | ||
| "ps256-sample-key", | ||
| now, | ||
| exp, | ||
| ); | ||
| } | ||
|
|
||
| #[allow(clippy::too_many_arguments)] | ||
| fn mint( | ||
| name: &str, | ||
| alg: Algorithm, | ||
| private_key_b64: &str, | ||
| public_key_b64: &str, | ||
| kid: &str, | ||
| iat: u64, | ||
| exp: u64, | ||
| ) { | ||
| let private_key = Base64::decode_to_vec(private_key_b64, None).expect("valid private key"); | ||
| let public_key = Base64::decode_to_vec(public_key_b64, None).expect("valid public key"); | ||
|
|
||
| let token = TokenBuilder::new() | ||
| .algorithm(alg) | ||
| .protected_key_id(KeyId::string(kid)) | ||
| .registered_claims( | ||
| RegisteredClaims::new() | ||
| .with_issuer("example-issuer") | ||
| .with_subject("example-subject") | ||
| .with_audience("example-audience") | ||
| .with_issued_at(iat) | ||
| .with_not_before(iat) | ||
| .with_expiration(exp), | ||
| ) | ||
| .sign(&private_key) | ||
| .expect("Failed to sign token"); | ||
|
|
||
| let token_bytes = token.to_bytes().expect("Failed to encode token"); | ||
| let hex = Hex::encode_to_string(&token_bytes).expect("hex encode"); | ||
| let b64url = Base64UrlSafeNoPadding::encode_to_string(&token_bytes).expect("b64url encode"); | ||
|
|
||
| // Sanity check: the token verifies against its public key. | ||
| let decoded = Token::from_bytes(&token_bytes).expect("decode"); | ||
| decoded.verify(&public_key).expect("verify signature"); | ||
| decoded | ||
| .verify_claims( | ||
| &VerificationOptions::new() | ||
| .verify_exp(true) | ||
| .verify_nbf(true) | ||
| .expected_issuer("example-issuer") | ||
| .expected_audience("example-audience"), | ||
| ) | ||
| .expect("verify claims"); | ||
|
|
||
| println!("=== {name} ==="); | ||
| println!("kid: {kid}"); | ||
| println!("public key (SPKI DER, base64): {public_key_b64}"); | ||
| println!("token length: {} bytes", token_bytes.len()); | ||
| println!("token (hex): {hex}"); | ||
| println!("token (b64url): {b64url}"); | ||
| println!(); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch — the PR description was stale. The code is correct at
1.88.0; I've updated the description to match and explain why (uncommittedCargo.lock→ downstream re-resolves tominicbor-derive 0.19.4which needs let-chains/1.88, andzeroize 1.9needs edition 2024/1.85). The pinnedmsrvCI job already builds+tests on1.88.0, so all three (Cargo.toml, CI, description) are now consistent.