Code Monkey home page Code Monkey logo

pasetors's Introduction

Tests Documentation Crates.io Safety Dance MSRV codecov

PASETOrs

"Paseto is everything you love about JOSE (JWT, JWE, JWS) without any of the many design deficits that plague the JOSE standards."

PASETO (Platform-Agnostic SEcurity TOkens) are secure stateless tokens. Read more here and at PASETO.io.

This library includes:

  • Pure-Rust implementation of the Version 4, 3โ€  and 2 protocol
  • PASERK support (limited amount of PASERK-types) with optional serde support as well
  • #![no_std] (with default-features disabled) and #![forbid(unsafe_code)]
  • WASM-friendly (wasm32-unknown-unknown using #![no_std])
  • Fuzzing targets
  • Test vectors
  • Usage examples

โ€  Only the public variant (v3.public) of version 3 is currently supported.

Usage

See usage examples here.

Security

This library has not undergone any third-party security audit. Usage is at own risk.

Minimum Supported Rust Version

Rust 1.72.0 or later is supported however, the majority of testing happens with latest stable Rust.

MSRV may be changed at any point and will not be considered a SemVer breaking change.

Changelog

Please refer to the CHANGELOG.md list.

License

pasetors is licensed under the MIT license. See the LICENSE file for more information.

pasetors's People

Contributors

brycx avatar dependabot-preview[bot] avatar dependabot[bot] avatar franklx avatar not-my-profile avatar sanchithhegde avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pasetors's Issues

Support local/public/secret PASERK types

In order to use Paseto for my application I need cross-language interoperability. However the only two Paseto v4 implementations for Python enforce Algorithm Lucidity, meaning they currently cannot be easily used in conjunction with pasetors, since it doesn't support Paserk.

So it would be great if pasetors could support importing/exporting keys from/to Paserk :)

Add WASM/ WebAssembly support

Hello, @brycx . Your library is awesome. I hope I can use pasetors in my web app.

Although there are libraries which already implement PASETO using javascript programming language, unfortunately those aren't running well in browser environment. Those libraries can be used in node.js environment (run javascript inside server). Converting existing library which can be used in browser is not an easy task.

Nowadays, rust can be compiled into WebAssembly (or WASM for short), and then can be used in browser. If you don't mind, could you add WASM support for this library?

Maybe Claims::new() should accept a Duration parameter?

Thanks for your hard work, it's a very good crate.

it's all works perfectly, expect when i trying to change the expiration time.
for example, using Claims::new() will create a claims expired in one hours, it's works fine.
but when i trying to change this, there is no easy way to do that, i had to write a helper function, like

fn helper_change_exp(claims: &mut Claims, duration: &Duration) {
  if let Some(Value::String(iat) = claims.get_claim("iat") {
    let iat = OffsetDateTime::parse(&iat, &Rfc3999).unwrap();
    let exp = (iat + *duration).format(&Rfc3999).unwrap();
    claims.expiration(&exp).unwrap();
}

or

fn helper_change_exp(claims: &mut Claims, duration: &Duration) {
  let iat = OffsetDateTime::now_utc();
  let nbf = iat;
  let mut exp = iat;
  exp += *duration;
 
  claims.issued_at(&iat.format(&Rfc3339).unwrap()).unwrap();
  claims.not_before(&nbf.format(&Rfc3339).unwrap()).unwrap();
  claims.expiration(&exp.format(&Rfc3339).unwrap()).unwrap();
}

if the Claims::new() can accept a Duration, it's will be more user friendly, like

pub fn new(duration: &Duration) -> Result<Self, Error> {
        let iat = OffsetDateTime:now:now_utc();
        let nbf = iat;
        let mut exp = iat;
        exp += *duration;

        let mut claims = Self {
            list_of: HashMap::new(),
        };

        claims.issued_at(&iat.format(&Rfc3339).map_err(|_| Error::InvalidClaim)?)?;
        claims.not_before(&nbf.format(&Rfc3339).map_err(|_| Error::InvalidClaim)?)?;
        claims.expiration(&exp.format(&Rfc3339).map_err(|_| Error::InvalidClaim)?)?;

        Ok(claims)
    }

then we can use Claims::new(&Duration::hours(3)), less code and easy to use.
could you please considering add this?
or maybe add a new new() function with another name for compatibility?

Switch from `ed25519-dalek` to `ed25519-compact`

The latter is more self-contained, has fewer dependencies which are also up to date. The dalek crate has been behind on rand versions for some time and the ed2559-compact uses fiat's formally-verified arithmetic for Ed25519. Additionally, the latter has all the functionality required by this crate as well.

Panic when running in WASM

Please let me know if this is not the right place to open this issue.

I've got a cloudflare worker running and I'm trying to create and verify pasetos, however there is a panic which seems to only happen on attempting to create a token. I'll include the code and behavior here.

use core::convert::TryFrom;
use pasetors::claims::{Claims, ClaimsValidationRules};
use pasetors::keys::SymmetricKey;
use pasetors::token::UntrustedToken;
use pasetors::{local, version4::V4, Local};
use std::error::Error;

pub fn mint(email: &str, key: &str) -> Result<String, Box<dyn Error>> {
    let mut claims = Claims::new()?;
    claims.subject(email)?;

    let sk = SymmetricKey::<V4>::from(key.as_bytes())?;
    let token = local::encrypt(&sk, &claims, None, Some(b"implicit assertion"))?;

    Ok(token)
}

pub fn verify(token: &str, key: &str) -> Result<Option<Claims>, Box<dyn Error>> {
    let validation_rules = ClaimsValidationRules::new();
    let untrusted_token = UntrustedToken::<Local, V4>::try_from(token)?;
    let sk = SymmetricKey::<V4>::from(key.as_bytes())?;
    let trusted_token = local::decrypt(&sk, &untrusted_token, &validation_rules, None, None)?;

    let claims = match trusted_token.payload_claims() {
        Some(c) => Some(c.to_owned()),
        None => None,
    };

    Ok(claims)
}

Observed behavior when calling mint:

panicked at 'time not implemented on this platform', library/std/src/sys/wasm/../unsupported/time.rs:31:9

plans for v3.public

What is your plans re v3.public will you be supporting it? If so do you have an ETA?

Provide `TryFrom<AsymmetricSecretKey> for AsymmetricPublicKey<>`

A user should be able to compute the public key from a given private key of the current versions v2, v3 and v4.

This should be straight forward with v2 and v4 since the ed25519 crates support the needed operations as part of their public API. In terms of v3, it seems this will require a dependency on fiat-crypto and implementing scalar multiplication with the curve base/generator. ring does not support computing a public key from the private and does not even have a type to represent a private key.

Based on discussion starting here: #40 (comment)

Implementation issues

I am currently using an implementation of paseto but it is currently not being maintained again. This crate, implementation, was recommended but I have issues implementing what I want. In the previous crate, I have these two functions:

...
pub fn issue_confirmation_token(user_id: uuid::Uuid) -> String {
    let settings = crate::settings::get_settings().expect("Cannot load settings.");
    let current_date_time = chrono::Utc::now();
    let dt = current_date_time + chrono::Duration::minutes(settings.secret.token_expiration);
    paseto::tokens::PasetoBuilder::new()
        .set_encryption_key(&Vec::from(settings.secret.secret_key.as_bytes()))
        .set_expiration(&dt)
        .set_not_before(&chrono::Utc::now())
        .set_claim("user_id", serde_json::json!(user_id))
        .build()
        .expect("Failed to construct paseto token w/ builder!")
}

pub async fn verify_confirmation_token(
    token: String,
) -> Result<crate::types::ConfirmationToken, String> {
    let settings = crate::settings::get_settings().expect("Cannot load settings.");
    let token = paseto::tokens::validate_local_token(
        &token,
        None,
        &settings.secret.secret_key.as_bytes(),
        &paseto::tokens::TimeBackend::Chrono,
    )
    .map_err(|e| format!("Paseto: {}", e))?;

    serde_json::from_value::<crate::types::ConfirmationToken>(token)
        .map_err(|e| format!("Serde_json: {}", e))
}
...

How can I achieve these with this crate. The examples in the docs ain't helping much and I had spent ample time trying to get this to work but all to no avail.

Feature gate local & public

Some applications might only need Paseto local, while some applicaitons might only need Paseto public. In either case they might want to avoid an unnecessary dependency on ed25519-dalek or orion respectively.

So I think the following would make sense:

[features]
default = [ "std", "local", "public" ]
std = [ "serde_json", "chrono" ]
local = [ "orion" ]
public = [ "ed25519-dalek" ]

The current dependency on orion::util::secure_cmp would need to be dropped (we can just directly depend on subtle).

To make docs.rs render feature badges we can employ this trick.

`0.5.0` tracker

These are the things remaining before 0.5.0 can be released:

  • Add test that test the version features enabled individually not just all at the same time
  • Audit error-variants for usage and clarity in context
  • Run test-suite on 32-bit target using cross
  • Switch to RustCrypto p384 crate once 0.11.0 has been released thereof, which will include P384 support (#55). RFC 6979 support still seems experimental, so we need to add an issue to switch to this in the future.
  • Update PASERK test vectors (#59)
  • Ensure fuzzing targets are up-to-date

We'd also want to update the listing on paseto.io to indicate we support v3.public.

cc @Eh2406

Relax payload from_utf8 behind flag

A minor suggestion

It would be nice if the payload could be relaxed to a non-valid utf-8 encoding, currently it restricts binary encodings. I know binary encoding, is not compliant with the PASETO RFC. As a suggestion, it could be hidden behind a feature flag to allow binary encodings and since the function signature for payload is &[u8], and a valid footer does not need a valid utf-8 encoding.

https://github.com/brycx/pasetors/blob/807d3ad3660158bac25be0f66768d84ee259323d/src/token.rs#L119C21-L119C21

Add `generate()` for `AsymmetricKeyPair`

A user should be able to easily generate an asymmetric keypair for v2, v3 and v4.

This should be straight forward with v2 and v4 since the ed25519 crates support the needed operations as part of their public API. In terms of v3, this will probably require pulling in the pkcs8 because this is the only format ring supports the keypair to be exported as. We can get the public key from ring with .public_key().as_ref() but need PKCS8 parsing for the private key.

Based on discussion starting here: #40 (comment)

Public key oracle in `AsymmetricSecretKey::from(bytes: &[u8])` for ed25519

In #65, we removed the public key as a parameter in sign() operations, re https://github.com/MystenLabs/ed25519-unsafe-libs. What wasn't caught back then and remains now, is the possibility to construct two different AsymmetricSecretKey's, with the same secret seed but different public keys, as the format is seed || pk. This is relevant in settings where the keys can come from to-some-degree untrusted sources.

Therefor, I wish to introduce a check that recomputes the public key from the seed and compares it to the provided. Whether or not this should be an optional check I'm not sure of yet. But at first glance, it seems as if this would be best added in Version::validate_secret_key() impl for V2 and V4, and simply fail if the public keys do not match. It does add some overhead, but increases misuse-resistance.

Edit: InVersion::validate_secret_key() is where the check will be and remain for now.

Ability to extract parts of untrusted tokens

A user should be able to extract the footer and message part of a untrusted token. We can realize this by introducing two new types: UntrustedToken and TrustedToken.

Previous discussion in #40 stated the use case of not knowing what the footer contains, but still wanting to verify it. So a user should be able to get the untrusted footer value and pass it to verify()/decrypt() in order for it to be validated. Note that the footer is both compared in constant time AND is part of the signature for public tokens and the authenticated additional data for the AAD for local tokens. This means, that even if the footer has been tampered with, the signature/tag validtion should fail. Sufficient warnings should be part of the documentation of the UntrustedToken and it's risks.

let untrsuted_token = UntrsutedToken::try_from(untrsuted_input)
// untrsuted_token.footer() -> returns Option(&'a [ u8])
let verify([..], [..], untrsuted_token.footer())?;

verify()/decrypt() functions could then return a TrustedToken with the ability to return the same individual parts of the verified token.

Based on discussion starting here: #40 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.