Skip to content
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

Initial Draft for PASETO v3/v4 specifications #127

Merged
merged 22 commits into from
Jul 30, 2021
Merged

Conversation

paragonie-security
Copy link
Contributor

@paragonie-security paragonie-security commented Jul 16, 2021

No Code Changes; only specification

See #128 for the implementation.

(Copied from Rationale-V3-V4.md)

Primary Motivations for New Versions

v4.local

v2.local was originally specified to use XChaCha20-Poly1305, a boring
AEAD mode that's obviously secure. However, we've since learned about
key- and message-commitment, which is an important security property
in systems with multiple possible symmetric keys.

Since PASETO added footers to support key-ids and key rotation
strategies, this means we MUST take attacks that depend on
random-key robustness seriously.

PASETO v4.local uses XChaCha20 to encrypt the message, but then uses
a keyed BLAKE2b hash (which acts as HMAC) for the authentication tag.

v3.public

We specified RSA for PASETO v1.public tokens, under the assumption that
applications that must ONLY support NIST algorithms (e.g. because they
MUST only use FIPS 140-2 validated modules to maintain compliance) would
be adequately served by RSA signatures. This assumption turned out to be
incorrect, and elliptic curve cryptography is now preferred.

To better meet the needs of applications that are NIST-dependent, PASETO
v3.public tokens will support ECDSA over NIST's P-384 curve, with SHA-384,
and (preferably) using RFC 6979 deterministic signatures. (RFC 6979 is a
SHOULD, not a MUST, due to library availability issues and
fault attacks.)

ECDSA Security

ECDSA is much more dangerous to implement than Ed25519:

  1. You have to ensure the one-time secret k is never reused for different
    messages, or you leak your secret key.
  2. If you're not generating k deterministically, you have to take extra
    care to ensure your random number generator isn't biased. If you fail
    to ensure this, attackers can determine your secret key through
    lattice attacks.
  3. The computing k^-1 (mod p) must be constant-time to avoid leaking k.
    • Most bignum libraries DO NOT provide a constant-time modular
      inverse function, but cryptography libraries often do. This is something
      a security auditor will need to verify for each implementation.

There are additional worries with ECDSA with different curves,
but we side-step most of these problems by hard-coding one NIST curve and
refusing to support any others. The outstanding problems are:

There are additional protocol-level security concerns for ECDSA, namely:

  • Invalid Curve Attacks, which are known to break ECDH.
    • This is solved in PASETO through requiring support for
      Point Compression.
    • Implementations MAY also optionally support PEM encoding of
      uncompressed public key points, but if they do, they MUST validate
      that the public key is a point on the curve.
    • Point compression used to be patented, but it expired. It's high time
      we stopped avoiding its usage as an industry.
  • Exclusive Ownership. See below.

Because of these concerns, we previously forbid any implementation of ECDSA
without RFC 6979 deterministic k-values in a future version.

However, given the real-world requirements of applications and systems that
must comply with NIST guidance on cryptography algorithms, we've relaxed this
requirement.

Additionally, deterministic k-values make signers more susceptible to fault
attacks than randomized signatures. If you're implementing PASETO signing in
embedded devices, or environments where fault injection may be a practical
risk, there are two things you can do:

  1. Don't use deterministic signatures because of your specific threat model.
  2. Hedged signatures: Inject additional randomness into the RFC 6979 step.
    This randomness doesn't need to be signed.

Questions For Security Auditors

Due to the risks inherent to ECDSA, security assessors should take care to
cover the following questions in any review of a PASETO implementation that
supports v3.public tokens (in addition to their own investigations).

  1. Is RFC 6979 supported and used by the implementation?
    1. If not, is a cryptographically secure random number generator used?
    2. If the answer to both questions is "No", fail.
  2. Is modular inversion (k^-1 (mod p)) constant-time?
    1. If not, fail.
  3. Are public keys expressed as compressed points?
    1. If not, is the public key explicitly validated to be on the correct
      curve (P-384)?
    2. If the answer to both questions is "No", fail.
  4. Does the underlying cryptography library use complete addition formulas
    for NIST P-384?
    1. If not, investigate how the library ensures that scalar multiplication
      is constant-time. (This affects the security of key generation.)

Affirmative answers to these questions should provide assurance that the
ECDSA implementation is safe to use with P-384, and security auditors can
focus their attention on other topics of interest.

v3.local / v4.public

No specific changes were needed from (v1.local, v2.public) respectively.
See below for some broader changes.

Beneficial Changes to V3/V4

No More Nonce-Hashing (Change)

The initial motivation for hashing the random nonce with the message was
to create an SIV-like construction to mitigate the consequences of weak
random number generators, such as OpenSSL's (which isn't
fork-safe).

However, this creates an unfortunate failure mode: If your RNG fails,
the resultant nonce is a hash of your message, which can be used to
perform offline attacks on the plaintext. This was first discovered by
Thái Dương.

To avoid this failure mode, neither v3.local nor v4.local will pre-hash
the message and random value to derive a nonce. Instead, it will trust
the CSPRNG to be secure.

Implicit Assertions (Feature)

PASETO v3 and v4 tokens will support optional additional authenticated
data that IS NOT stored in the token, but IS USED to calculate the
authentication tag (local) or signature (public).

These are called implicit assertions. These can be any application-specific
data that must be provided when validating tokens, but isn't appropriate to
store in the token itself (e.g. sensitive internal values).

One example where implicit assertions might be desirable is ensuring that a PASETO
is only used by a specific user in a multi-tenant system. Simply providing the
user's account ID when minting and consuming PASETOs will bind the token to the
desired context.

Better Use of HKDF Salts (Change)

With v1.local, half of the 32-byte random value was used as an HKDF salt and
half was used as an AES-CTR nonce. This is tricky to analyze and didn't extend
well for the v4.local proposal.

For the sake of consistency and easy-to-analyze security designs, in both v3.local
and v4.local, we now use the entire 32-byte random value in the HKDF step.

Instead of being used as a salt, however, it will be appended to the info tag.
This subtle change allows us to use the
standard security definition for HKDF
in arguments for PASETO's security, rather than treating it as just a
pseudo-random function (PRF). This security definition requires only one salt
to be used, but for many contexts (info tags).

The nonce used by AES-256-CTR and XChaCha20 will be derived from the HKDF output
(which is now 48 bytes for v3.local and 56 bytes for v4.local). The first 32
bytes of each HKDF output will be used as the key. The remaining bytes will be
used as the nonce for the underlying cipher.

Local PASETOs in v3 and v4 will always have a predictable storage size, and the
security of these constructions is more obvious:

  • The probability space for either mode is 256-bits of randomness + 256-bits of
    key, for a total of 512 bits.
    • The HKDF output in v3.local is 384 bits.
    • The HKDF output in v4.local is 448 bits.
    • Neither of these output sizes reduces the security against collisions.
      (If they were larger than the input domain of 512 bits, that would be a
      blunder.)
  • A single key can be used for 2^112 PASETOs before rotation is necessary.
    • The birthday bound for a 256-bit salt is 2^128 (for a 50% chance of
      a single collision occurring). Setting the safety threshold to 2^-32
      (which is roughly a 1 in 4 billion chance) for a space of 2^256
      yields 2^112.
  • The actual nonce passed to AES-CTR and XChaCha is not revealed publicly.

V3 Signatures Prove Exclusive Ownership (Enhancement)

RSA and ECDSA signatures do not prove Exclusive Ownership.
This is almost never a problem for most protocols, unless you expect this property
to hold when it doesn't.

Section 3.3 of the paper linked above describes how to achieve Universal Exclusive
Ownership (UEO) without increasing the signature size: Always include the public
key in the message that's being signed.

Consequently, v3.public PASETOs will include the raw bytes of the public
key in the PAE step for calculating signatures. The public key is always a
compressed point (0x02 or 0x03, followed by the X coordinate, for a total
of 49 bytes).

We decided to use point compression in the construction of the tokens as a
forcing function so that all PASETO implementations support compressed points
(and don't just phone it in with PEM-encoded uncompressed points).

Ed25519, by design, does not suffer from this,
since Ed25519 already includes public key with the hash function when signing
messages. Therefore, we can safely omit this extra step in v4.public tokens.

Miscellaneous Changes

Define Mechanism for Extending PASETO for non-JSON Encodings

PASETO serializes its payload as a JSON string. Future documents MAY specify using
PASETO with non-JSON encoding. When this happens, a suffix will be appended to the version tag
when a non-JSON encoding rule is used.

For example, a future PASETO-CBOR proposal might define its versions as v1c, v2c, v3c,
and v4c. The underlying cryptography will be the same as v1, v2, v3, and v4
respectively. Keys SHOULD be portable across different underlying encodings, but tokens
MUST NOT be transmutable between encodings without access to the symmetric key (local tokens)
or secret key (public tokens).

Questions and Answers

Why Not AES-GCM in v3.local?

While it's true that AES-GCM is more broadly supported in environments that use
NIST and FIPS-approved cryptography, GMAC is neither
message-committing nor key-committing.

The techniques for turning an AEAD scheme into an AEAD scheme is well known,
but it requires publishing an additional SHA2 hash (or KDF output) of the
key being used.

Using GCM would require us to also publish an additional hash anyway. At
that point, it doesn't offer any clear advantage over CTR+HMAC.

CTR+HMAC (with separate keys and PAE) is a secure construction and provides
the cryptographic properties we need to use PASETO in threat models where
multiple keys are used or partitioning oracles
are possible.

Why P-384 in v3.public instead of P-256 or P-521?

Security experts that work heavily with NIST algorithms expressed a
slight preference for P-384 over P-521 and P-256 when we asked. This is also
congruent for our choice of SHA-384 as a hash function over SHA-256 or SHA-512.

The security considerations for the NIST curves are mostly
congruent (albeit the ECDLP security and performance differs a bit).

If you want smaller tokens or better performance than P-384, make sure Ed25519
lands in FIPS 186-5 and use v4.public instead.

@panva
Copy link
Contributor

panva commented Jul 17, 2021

👋

  • v3.public should have the signature encoding specified, whether it's DER-encoded ASN.1 or the more compact (and imho more fitting) IEEE-P1363 proposed r || s representation. The former is already encoded which we then encode again with base64url, bloating the final token size as a result. 6-8 bytes of the signature itself can be shaved off when using IEEE-P1363 proposed r || s representation. Furthermore the signature lengths when using DER differ, making it more error-prone to split m and s when verifying.
  • I'm not that into the building blocks to know whether RFC 6979 deterministic k-values come out of the box in existing crypto abstractions over openssl, but if it means that the same input data always generates the same signature than this is not achievable in a number of openssl backed crypto systems, e.g. Node.js crypto module. Two signatures over the same data will always be different, there's no option to make it otherwise.
  • implicit assertions 👍

Edit: it seems IEEE-P1363 style signature is already implied given that the verify step 3 says to the rightmost 96 bytes

Edit2: RFC 6979 is indeed not supported by openssl yet. It is unfortunate that because of this yet another version.purpose can't be supported without bundling additional crypto runtimes like libsodium into openssl-capable environments.

@paragonie-security
Copy link
Contributor Author

The intent of RFC 6979 is to be compatible with FIPS 186-5 when it's no longer a draft.

However, there is also the argument that randomness makes some side-channel attacks more difficult in certain environments. Consequently, the IETF has shown interest in so-called hedged signatures.

Relaxing this restriction may be pragmatic but it's still dangerous.

@paragonie-security
Copy link
Contributor Author

We've relaxed the RFC 6979 requirement from MUST to SHOULD. When it's not possible, a CSPRNG MUST be used for k-value generation.

@paragonie-security
Copy link
Contributor Author

paragonie-security commented Jul 18, 2021

I'm going to quickly tag everyone who has contributed a PASETO implementation so they're aware of v3/v4 and have ample opportunity to provide feedback.

@sjudson @peter-evans @nbaars @atholbro @sethbattin @minus7 @eislambey @bdemers @scottbrady91 @shuLhan @brycx @vk-rv @o1egl @Ianleeclark @shuLhan @daviddesmet @dustinsoftware @bricej13 @rlittlefield @mguymon @AnIrishDuck @aidantwoods

Copy link
Contributor

@panva panva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given a JWK representation of a public key, e.g.

{
  crv: 'P-384',
  kty: 'EC',
  x: 'lkB6sw4ohIlg00fBle-TzK8_OyUGNpE74vhi1BQ45NkCJtscEV1BUdrzhk_OTrvP',
  y: 'fH7l2JEKPnR3pywmodMy6pBIi_h7JxwuQoPYhF5REvGwuJUxPlNSWBCj7IvxKdmq'
}

What is the pk to pack in v3.public.? Is it as simple as sign followed by x where sign is 0x02 if y is even, 0x03 if y is odd?

NB: SPKI representation of the same key

-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAElkB6sw4ohIlg00fBle+TzK8/OyUGNpE7
4vhi1BQ45NkCJtscEV1BUdrzhk/OTrvPfH7l2JEKPnR3pywmodMy6pBIi/h7Jxwu
QoPYhF5REvGwuJUxPlNSWBCj7IvxKdmq
-----END PUBLIC KEY-----

panva added a commit to panva/paseto that referenced this pull request Jul 18, 2021
@Mythra
Copy link

Mythra commented Jul 18, 2021

I've also contributed an implementation (the first rust one) and luckily just happened to check my email 😅 to see this.

I don't see any problems with this on the start -- for rust it might be a little tough since: crypto_stream_xchacha20_xor is from libsodium (whose currently in a murky state looking for maintainers: https://github.com/sodiumoxide/sodiumoxide/issues/442 -- and we don't have any crate in the Rust-Crypto/dalek-cryptography/etc. that does this particular flavor of XOR'ing xchacha , just normal XChaCha). Though I'm not going to say this shouldn't move forward just because one language doesn't have a good way to use a solid proven crypto library that we honestly should support.

Otherwise this all seems fairly cut and dry. Thanks for getting this out.

@paragonie-security
Copy link
Contributor Author

Given a JWK representation of a public key, e.g.

{
  crv: 'P-384',
  kty: 'EC',
  x: 'lkB6sw4ohIlg00fBle-TzK8_OyUGNpE74vhi1BQ45NkCJtscEV1BUdrzhk_OTrvP',
  y: 'fH7l2JEKPnR3pywmodMy6pBIi_h7JxwuQoPYhF5REvGwuJUxPlNSWBCj7IvxKdmq'
}

The public key, when hex-encoded, will look like this:

0296407ab30e28848960d347c195ef93ccaf3f3b250636913be2f862d41438e4d90226db1c115d4151daf3864fce4ebbcf

What is the pk to pack in v3.public.? Is it as simple as sign followed by x where sign is 0x02 if y is even, 0x03 if y is odd?

Online documentation for this appears to be unclear about which bit of y to use to determine 02 vs 03, but every library we've studied just uses odd/even as the determinant, and this makes sense.

@panva
Copy link
Contributor

panva commented Jul 18, 2021

Given a JWK representation of a public key, e.g.

{
  crv: 'P-384',
  kty: 'EC',
  x: 'lkB6sw4ohIlg00fBle-TzK8_OyUGNpE74vhi1BQ45NkCJtscEV1BUdrzhk_OTrvP',
  y: 'fH7l2JEKPnR3pywmodMy6pBIi_h7JxwuQoPYhF5REvGwuJUxPlNSWBCj7IvxKdmq'
}

The public key, when hex-encoded, will look like this:

0296407ab30e28848960d347c195ef93ccaf3f3b250636913be2f862d41438e4d90226db1c115d4151daf3864fce4ebbcf

What is the pk to pack in v3.public.? Is it as simple as sign followed by x where sign is 0x02 if y is even, 0x03 if y is odd?

Online documentation for this appears to be unclear about which bit of y to use to determine 02 vs 03, but every library we've studied just uses odd/even as the determinant, and this makes sense.

If it's unclear, why not use the uncompressed representation instead?

@paragonie-security
Copy link
Contributor Author

I've also contributed an implementation (the first rust one) and luckily just happened to check my email 😅 to see this.

Sorry about the oversight; I was gauging based on pull requests. I'll make sure I didn't miss anyone.

I don't see any problems with this on the start -- for rust it might be a little tough since: crypto_stream_xchacha20_xor is from libsodium (whose currently in a murky state looking for maintainers: sodiumoxide/sodiumoxide#442 -- and we don't have any crate in the Rust-Crypto/dalek-cryptography/etc. that does this particular flavor of XOR'ing xchacha , just normal XChaCha). Though I'm not going to say this shouldn't move forward just because one language doesn't have a good way to use a solid proven crypto library that we honestly should support.

Otherwise this all seems fairly cut and dry. Thanks for getting this out.

I think this should be an easy patch to write. Let me follow up with the crypto rustaceans I know and hopefully we can prevent this from making PASETO painful to implement.

@paragonie-security
Copy link
Contributor Author

If it's unclear, why not use the uncompressed representation instead?

What's unclear is the informal answers you find on forums like Stack Exchange, not the SECGv2 paper. Its definition is very precise.

Compressed points prevent implementations from accidentally becoming susceptible to off-curve attacks. e.g. https://auth0.com/blog/critical-vulnerability-in-json-web-encryption/

@brycx
Copy link

brycx commented Jul 18, 2021

and we don't have any crate in the Rust-Crypto/dalek-cryptography/etc. that does this particular flavor of XOR'ing xchacha , just normal XChaCha)

@Mythra

Just FYI, the difference is simply that the XOR'ing flavor XORs the XChaCha pseduo-random stream with the input plaintext. Should be straight-forward if plain XChaCha is available.

Orion (disclaimer: I'm the maintainer) supports this XORing flavor, for inspiration. Not as battle-tested as libsodium though.

@Mythra
Copy link

Mythra commented Jul 18, 2021

@brycx thanks. I had figured it wouldn't be too hard but to be honest I don't trust myself to make those determinations.

I didn't see Orion -- guess my GoogleFu was weak. But it's good to know there's some prior art.

@panva
Copy link
Contributor

panva commented Jul 18, 2021

Compressed points prevent implementations from accidentally becoming susceptible to off-curve attacks. e.g. auth0.com/blog/critical-vulnerability-in-json-web-encryption

I'm aware of that, but it makes little difference to the Exclusive Ownership enhancement itself, doesn't it?

For the record I'm okay with either, I am just looking at ways of making this less error-prone when it comes to interoperability of implementations.

As a bit of feedback, when it comes to vectors it would be amazing if key representations were provided in various formats - compressed public, SPKI PEM as well as JWK.

@brycx
Copy link

brycx commented Jul 18, 2021

@paragonie-security Thanks for the ping. I'll be taking a closer look when implementing, but seems good to me so far. Glad to see the focus on key-commitment.

Re the XChaCha20-Blake2b construction: Are there existing test vectors for this combination available, outside the context of PASETO, or will implementers have to rely on the implicit test vectors through PASETO only?

Thanks for the work you've put into this!

@paragonie-security
Copy link
Contributor Author

Compressed points prevent implementations from accidentally becoming susceptible to off-curve attacks. e.g. auth0.com/blog/critical-vulnerability-in-json-web-encryption

I'm aware of that, but it makes little difference to the Exclusive Ownership enhancement itself, doesn't it?

They're not just used in the EO enhancement, but also a MUST for the actual public key encoding for PASETO v3.

For the record I'm okay with either, I am just looking at ways of making this less error-prone when it comes to interoperability of implementations.

As a bit of feedback, when it comes to vectors it would be amazing if key representations were provided in various formats - compressed public, SPKI PEM as well as JWK.

There will be test vectors. We're also working on a related specification for key serialization right now to obviate JWK, but we have no problem building test vectors from (x, y) pairs that can be JWK-alike.

@paragonie-security
Copy link
Contributor Author

paragonie-security commented Jul 18, 2021

Re the XChaCha20-Blake2b construction: Are there existing test vectors for this combination available, outside the context of PASETO, or will implementers have to rely on the implicit test vectors through PASETO only?

Halite has been using this construction for years (albeit with Salsa20 instead of ChaCha). Halite v5 will almost certainly use XChaCha.

@kdenhartog
Copy link

kdenhartog commented Jul 19, 2021

Given a JWK representation of a public key, e.g.

{
  crv: 'P-384',
  kty: 'EC',
  x: 'lkB6sw4ohIlg00fBle-TzK8_OyUGNpE74vhi1BQ45NkCJtscEV1BUdrzhk_OTrvP',
  y: 'fH7l2JEKPnR3pywmodMy6pBIi_h7JxwuQoPYhF5REvGwuJUxPlNSWBCj7IvxKdmq'
}

The public key, when hex-encoded, will look like this:

0296407ab30e28848960d347c195ef93ccaf3f3b250636913be2f862d41438e4d90226db1c115d4151daf3864fce4ebbcf

What is the pk to pack in v3.public.? Is it as simple as sign followed by x where sign is 0x02 if y is even, 0x03 if y is odd?

Online documentation for this appears to be unclear about which bit of y to use to determine 02 vs 03, but every library we've studied just uses odd/even as the determinant, and this makes sense.

I typically reference section 4.3.6 step 2.2 of this document 1 for point compression. It seems to be the normative way that sec2 originally defined it and has been reliably interoperable for us when dealing with compressed key formats from the secg curves. It aligns with the way you pointed out as well which is sign based on if it's even or odd. Does that help as a point of reference?

@panva
Copy link
Contributor

panva commented Jul 19, 2021

Does that help as a point of reference?

@kdenhartog it sure does, thank you.

@paragonie-security
Copy link
Contributor Author

I've pushed a commit (and updated the top-level comment) to explain the operational security requirements imposed by ECDSA for v3.public tokens.

@paragonie-security
Copy link
Contributor Author

A mechanism that should remain uncontroversial is to enforce a maximum depth of N (where N is very small; for example, 2). If you're storing expressive claims, that probably doesn't belong in the footer.

@paragonie-security
Copy link
Contributor Author

@panva

v2 and v4 I cannot check though

a355cfb corrects v2/v4 and adds PHP code to verify the JSON as part of CI

@bdemers
Copy link

bdemers commented Jul 28, 2021

I agree, but setting the max depth of a JSON parser may not be possible depending on the JSON lib used (and resolving it after the fact is too late)

This section in the spec implies the footer could be used to store data for "unencrypted, but authenticated, tokens"
https://github.com/paragonie/paseto/pull/127/files#diff-0b5ca119d2be595aa307d34512d9679e49186307ef94201e4b3dfa079aa89938R45-R47

If a kid was also contained in the footer for this scenario, that might make it more challenging to guard against depth size as well.

@paragonie-security
Copy link
Contributor Author

How exactly would you recommend enforcing this safely?

@paragonie-security
Copy link
Contributor Author

To expand our previous query with a little more context:

One of the mechanisms we're introducing with PASERK is the ability to wrap a single token key against multiple wrapping keys (local-seal, local-wrap.pie., local-wrap.customwrapper., etc.).

(PASERK is one motivation for why V3/V4 must be RKR-secure and why V3 always supports point compression for P-384 keys.)

It's very possible that someone will want to use PASETO with PASERK such that there is no one kid in the footer, but rather, a bundle of 2 or more encrypted representations of the same plaintext symmetric key. Visually:

footer = JSON.stringify({
    "wrapped-keys": [
        "k4.seal.AAAAAAAAAAAAA...",
        "k4.local-wrap.pie.AAA..."
    ]
})

Alternatively, if there's only one wrapped key, it's reasonable to only use that as the footer.

footer = "k4.local-wrap.pie.AAA..."

If JSON in the footer is a security problem for Java libraries, then PASETO needs to try to mitigate it at a design level. (That doesn't guarantee that we'll succeed, but it's a good use of our time.)

…rsers

We're actively looking for more feedback on this
@paragonie-security
Copy link
Contributor Author

paragonie-security commented Jul 28, 2021

2df496e adds a Parser rule called FooterJSON that allows assertions to be made about the footer:

  1. Maximum number of object keys
  2. Maximum length of the JSON string
  3. Maximum recursive depth (this is the last check, because in PHP, it requires decoding the string to assert)

EDIT: 1e2daa2 makes it reject tokens that are too deep without needing to actually parse it with a JSON library.

This rule should make it more difficult to target PASETO with Hash-DoS attacks. @bdemers what do you think?

@paragonie-security
Copy link
Contributor Author

@bdemers We provided an algorithm for validating the maximum stack size of an arbitrary JSON string without depending on a JSON parser in 190e1b8

An example implementation can be found in #128.

@panva
Copy link
Contributor

panva commented Jul 29, 2021

@paragonie-security in the typescript example -> Step 6 is an infinite loop. Give it a whirl with the following inputs: getJsonDepth('{"foo":"bar"}'), getJsonDepth('{}')

@purificant
Copy link

All 12 v2 test vectors are working fine against my implementation, 3 for v2.public plus 9 for v2.local as seen here

Do I understand correctly that implicit assertions are a new v3 / v4 feature and won't be a feature in v1 / v2? I noticed that implicit-assertion field is also included in the v2 test vectors.

@paragonie-security
Copy link
Contributor Author

@paragonie-security in the typescript example -> Step 6 is an infinite loop. Give it a whirl with the following inputs: getJsonDepth('{"foo":"bar"}'), getJsonDepth('{}')

I must've made a mistake with my regex. Thanks for checking, I'll fix it.

All 12 v2 test vectors are working fine against my implementation, 3 for v2.public plus 9 for v2.local as seen here

Excellent!

Do I understand correctly that implicit assertions are a new v3 / v4 feature and won't be a feature in v1 / v2? I noticed that implicit-assertion field is also included in the v2 test vectors.

Yes, their inclusion in the test vectors was to signal that they are not supported in v1/v2. The main reason is that there are over a dozen v1/v2 implementations in the wild and none of them supported this feature, so it would be breaking backwards compatibility.

@bdemers
Copy link

bdemers commented Jul 29, 2021

I had been thinking about using the footer text as the kid, but I hadn't thought about the complex object keys use case (thanks for adding that example above).

An additional challenge with any option is there is no standard key rotation mechanism. This isn't a PASETO spec problem though, I'm guessing that would/should be defined in any spec that depends on PASETO.

But this does mean the implementations need to pass this flexibility down to the user/developer of a PASETO lib (this is already spelled out in the guides). Ideally, there would be a single definitive way to get a key-id. That said, my musing on this is probably short-sighted given the complex keys mentioned above and the simple fact any sort of key-id representation is optional.

I'm mostly thinking out loud anyway, but your resulting JSON bits are a great addition to the guide!

@paragonie-security
Copy link
Contributor Author

I had been thinking about using the footer text as the kid, but I hadn't thought about the complex object keys use case (thanks for adding that example above).

An additional challenge with any option is there is no standard key rotation mechanism. This isn't a PASETO spec problem though, I'm guessing that would/should be defined in any spec that depends on PASETO.

But this does mean the implementations need to pass this flexibility down to the user/developer of a PASETO lib (this is already spelled out in the guides). Ideally, there would be a single definitive way to get a key-id. That said, my musing on this is probably short-sighted given the complex keys mentioned above and the simple fact any sort of key-id representation is optional.

You can use PASERK to serialize local or public keys and either stick them in the footer or send them out-of-band (and include them as an implicit assertion in v3/v4).

I'm mostly thinking out loud anyway, but your resulting JSON bits are a great addition to the guide!

Thanks! I hope it helps.

@paragonie-security
Copy link
Contributor Author

We changed the way HKDF is used in Version 3 of PASETO: 6c6eb51

@panva

This comment has been minimized.

@paragonie-security
Copy link
Contributor Author

It looks like we agree: 7e72e5f

Version 3 is defined as follows:

- NIST P-384: 192-bit security level
- AES-256-CTR: 256-bit security level
- HMAC-SHA-384: 192-bit security level

...why were we using 256-bit keys (128-bit birthday collision level) and reducing the security if the authentication tag is already 48 bytes?

This change makes V3's cryptographic primitives consistently at or above the 192-bit security level.
@paragonie-security
Copy link
Contributor Author

paragonie-security commented Jul 29, 2021

Updated 3-E-* test vectors with 092629c

v3.local.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbfcIURX_0pVZVU1mAESUzrKZAsRm2EsD6yBoZYn6cpVZNzSJOhSDN-sRaWjfLU-yn9OJH1J_B8GKtOQ9gSQlb8yk9Iza7teRdkiR89ZFyvPPsVjjFiepFUVcMa-LP18zV77f_crJrVXWa5PDNRkCSeHfBBeg
v3.local.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADbfcIURX_0pVZVU1mAESUzrKZAqhWxBMDgyBoZYn6cpVZNzSJOhSDN-sRaWjfLU-yn9OJH1J_B8GKtOQ9gSQlb8yk9IzZfaZpReVpHlDSwfuygx1riVXYVs-UjcrG_apl9oz3jCVmmJbRuKn5ZfD8mHz2db0A
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0ROIIykcrGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJlxnt5xyhQjFJomwnt7WW_7r2VT0G704ifult011-TgLCyQ2X8imQhniG_hAQ4BydM
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0X-4P3EcxGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJlBZa_gOpVj4gv0M9lV6Pwjp8JS_MmaZaTA1LLTULXybOBZ2S4xMbYqYmDRhh3IgEk
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0ROIIykcrGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJlkYSIbXOgVuIQL65UMdW9WcjOpmqvjqD40NNzed-XPqn1T3w-bJvitYpUJL_rmihc.eyJraWQiOiJVYmtLOFk2aXY0R1poRnA2VHgzSVdMV0xmTlhTRXZKY2RUM3pkUjY1WVp4byJ9
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0X-4P3EcxGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJmSeEMphEWHiwtDKJftg41O1F8Hat-8kQ82ZIAMFqkx9q5VkWlxZke9ZzMBbb3Znfo.eyJraWQiOiJVYmtLOFk2aXY0R1poRnA2VHgzSVdMV0xmTlhTRXZKY2RUM3pkUjY1WVp4byJ9
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0ROIIykcrGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJkzWACWAIoVa0bz7EWSBoTEnS8MvGBYHHo6t6mJunPrFR9JKXFCc0obwz5N-pxFLOc.eyJraWQiOiJVYmtLOFk2aXY0R1poRnA2VHgzSVdMV0xmTlhTRXZKY2RUM3pkUjY1WVp4byJ9
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0X-4P3EcxGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJmZHSSKYR6AnPYJV6gpHtx6dLakIG_AOPhu8vKexNyrv5_1qoom6_NaPGecoiz6fR8.eyJraWQiOiJVYmtLOFk2aXY0R1poRnA2VHgzSVdMV0xmTlhTRXZKY2RUM3pkUjY1WVp4byJ9
v3.local.JvdVM1RIKh2R1HhGJ4VLjaa4BCp5ZlI8K0BOjbvn9_LwY78vQnDait-Q-sjhF88dG2B0X-4P3EcxGHn8wzPbTrqObHhyoKpjy3cwZQzLdiwRsdEK5SDvl02_HjWKJW2oqGMOQJlk1nli0_wijTH_vCuRwckEDc82QWK8-lG2fT9wQF271sgbVRVPjm0LwMQZkvvamqU.YXJiaXRyYXJ5LXN0cmluZy10aGF0LWlzbid0LWpzb24

@paragonie-security
Copy link
Contributor Author

Barring any discoveries from cryptography experts, that should be the last change we've made to V3/V4. Thanks for your patience and diligence @panva!

There are no significant changes as far as active implementations are concerned.

The only thing "noteworthy" is the delineation between the version (which is format-agnostic) and the token (which is JSON-specific) in naming convention.

This is so that future designers might specify PASETO over an encoding format other than JSON (Protobuf, CBOR, etc.) without having to re-define the cryptography protocols. If this happens, `v4c` would be simply, "Version 4 with CBOR".

You can think of the tokens as `v4j` if that helps (although JSON gets "no suffix" reserved for it).

If you don't care about these kinds of future-proofing discussions, then this commit will be uninteresting to you.
@paragonie-security
Copy link
Contributor Author

Due to the feedback we've received since this PR was opened (and a UX problem with Github), we're doing to merge this, but don't take that as a signal that discussion has closed prematurely. If you have any additional feedback, questions, concerns, etc. please raise them here or in a new issue (whichever you prefer).

Per #128, the comment period is open until at least 2021-08-02, but you should take us releasing v2.0.0 of this library as the signal that the design is final.

@paragonie-security paragonie-security merged commit aa05b70 into master Jul 30, 2021
@paragonie-security paragonie-security deleted the new-versions branch July 30, 2021 11:54
@paragonie-security
Copy link
Contributor Author

Per #78 we've moved the documentation to https://github.com/paseto-standard/paseto-spec

Please feel free to toss issues at that repository.

@paragonie-security
Copy link
Contributor Author

Spec has been finalized. v2.0.0 release incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants