Subject: Re: [IPsec] [Technical Errata Reported] RFC8031 (6339)

From: Benjamin Kaduk <[email-masked]>
Date: Sun, 6 Dec 2020 15:11:46 -0800

Can anyone speak to the history of the examples here (or the content of the
report itself)?

Thanks,

Ben

On Tue, Nov 17, 2020 at 10:46:21AM -0800, RFC Errata System wrote:
> The following errata report has been submitted for RFC8031,
> "Curve25519 and Curve448 for the Internet Key Exchange Protocol Version 2 (IKEv2) Key Agreement".
> 
> --------------------------------------
> You may review the report below and at:
> https://www.rfc-editor.org/errata/eid6339
> 
> --------------------------------------
> Type: Technical
> Reported by: Christian Tschudin <[email-masked]>
> 
> Section: Appendix A
> 
> Original Text
> -------------
> The public keys are generated from this using the formula in
> Section 2:
> 
> pub_i = X25519(d_i, G) =
>              48 d5 dd d4 06 12 57 ba 16 6f a3 f9 bb db 74 f1
>              a4 e8 1c 08 93 84 fa 77 f7 90 70 9f 0d fb c7 66
> 
> pub_r = X25519(d_r, G) =
>              0b e7 c1 f5 aa d8 7d 7e 44 86 62 67 32 98 a4 43
>              47 8b 85 97 45 17 9e af 56 4c 79 c0 ef 6e ee 25
> 
> And this is the value of the Key Exchange Data field in the Key
> Exchange payload described in Section 3.1.  The shared value is
> calculated as in Section 2:
> 
> SHARED_SECRET = X25519(d_i, pub_r) = X25519(d_r, pub_i) =
>              c7 49 50 60 7a 12 32 7f-32 04 d9 4b 68 25 bf b0
>              68 b7 f8 31 9a 9e 37 08-ed 3d 43 ce 81 30 c9 50
> 
> 
> Corrected Text
> --------------
> The public keys are generated from this using the formula in
> Section 2:
> 
> pub_i = X25519(d_i, G) =
>              a7 07 b3 bc 0f 37 56 fc 0a cf 33 55 85 c5 f7 7b
>              9f 29 ff a4 24 70 14 af 84 70 5b eb 50 46 26 29
> 
> pub_r = X25519(d_r, G) =
>              0e 57 7e 11 5d 6c 08 59 b8 51 36 d2 1b 1c fd 74
>              67 9f 91 14 61 1d 79 c6 81 ba d0 8a 7e 1f 0a 04
> 
> And this is the value of the Key Exchange Data field in the Key
> Exchange payload described in Section 3.1.  The shared value is
> calculated as in Section 2:
> 
> SHARED_SECRET = X25519(d_i, pub_r) = X25519(d_r, pub_i) =
>              d6 8d 8c ea fd 2c d3 ce 25 34 43 33 c8 9e 35 54
>              9e 0f c6 1a 98 87 39 34 b1 8a 18 70 f0 3a 17 0c
> 
> 
> Notes
> -----
> The test vector values given both for the public keys and for the shared secret are wrong. It turns out that they were derived from the unchanged random input, instead of d_X. An explanation could be that a first text version did not include the fixing of the random bits and that after inserting the respective paragraph (introducing fixed_X and d_X), it was forgotten to update pub_X and SHARED_SECRET.
> 
> This discrepancy came to my attention when testing the Yubikey 5 hardware and comparing it with the NaCl library and RFC8031. While the NaCl library works as expected, it is disturbing to see that the Yubikey can only be made to produce the desired (above and corrected) shared secret if you let it compute X25519(fixed_i,pub_r). That is, the secret must be presented to the Yubikey in big-endian format which could be "inspired" by the (not very detailed) Smartcard spec 3.4.1 that refers to ANSI X9.62 where curve parameters, prefixed with 0x04, are encoded in big-endian order - clearly the ANSI encoding is not useful here as we only need one parameter u. I wonder whether RFC8031 should spell out that input parameters (d_X and pub_X) SHOULD be presented in encoded form (and thus little-endian), hence putting manufacturers in charge of documenting any deviation.
> 
> Instructions:
> -------------
> This erratum is currently posted as "Reported". If necessary, please
> use "Reply All" to discuss whether it should be verified or
> rejected. When a decision is reached, the verifying party  
> can log in to change the status and edit the report, if necessary. 
> 
> --------------------------------------
> RFC8031 (draft-ietf-ipsecme-safecurves-05)
> --------------------------------------
> Title               : Curve25519 and Curve448 for the Internet Key Exchange Protocol Version 2 (IKEv2) Key Agreement
> Publication Date    : December 2016
> Author(s)           : Y. Nir, S. Josefsson
> Category            : PROPOSED STANDARD
> Source              : IP Security Maintenance and Extensions
> Area                : Security
> Stream              : IETF
> Verifying Party     : IESG

---

From: Jonathan Hammell <[email-masked]>
Date: Wed, 16 Dec 2020 14:02:43 -0500

I verified that the example in Appendix A of RFC 8031 is incorrect as
reported, but I do not believe that updating the values as suggested
in this errata completely fixes the example.

The corrected values given in the report are valid if they are
interpreted as little-endian encoded coordinates (i.e. apply
decodeUCoordinate from RFC 7448). However, RFC 8031 (and the reporter)
represented pub_i, pub_r and SHARED_SECRET as a byte-separated
strings, whereas earlier values in 8031 in this byte-separated format
(random_i, random_r, fixed_i, fixed_r) all appear to be in big endian
order and the d_i and d_r explicitly encoded in little-endian are
given as a single string. Therefore, I think the pub_i, pub_r,
SHARED_SECRET values should be in big endian order if they are
byte-separated, or as a single little-endian encoded string (i.e.
remove the spacings between bytes).

Additionally, I believe that fixed_i and fixed_r are incorrect
according to the clamping procedure from RFC 7748 (i.e.
decodeScalar25519). This decodeScalar25519 can be unambiguously
applied directly to the given d_i and this should result in fixed_i.
However, the least significant byte of decodeScalar25519(d_i) is 0x50
not matching 0x54 in fixed_i. Similarly, the most significant byte of
decodeScalar25519(d_r) is 0x48 not matching 0x08 in fixed_r. It would
appear that the clamping was incorrectly applied to the big-endian
ordered strings, random_i and random_r, to obtain the fixed_i and
fixed_r values in the RFC.

So to correct this, we should have

  fixed_i = 70 1f b4 30 86 55 b4 76 b6 78 9b 73 25 f9 ea 8c
             dd d1 6a 58 53 3f f6 d9 e6 00 09 46 4a 5f 9d 50

  fixed_r = 48 54 64 52 53 29 0d 60 dd ad d0 e0 30 ba cd 9e
             55 01 ef dc 22 07 55 a1 e9 78 f1 b8 39 a0 56 48

and random_i and random_r must be also updated to account for the
clamping applied on the little-endian ordered bytes, allowing some
freedom in choice of the bits masked out. For example, one could use

  random_i = b0 1f b4 30 86 55 b4 76 b6 78 9b 73 25 f9 ea 8c
             dd d1 6a 58 53 3f f6 d9 e6 00 09 46 4a 5f 9d 56

  random_r = 88 54 64 52 53 29 0d 60 dd ad d0 e0 30 ba cd 9e
             55 01 ef dc 22 07 55 a1 e9 78 f1 b8 39 a0 56 4a

Jonathan

On Sun, Dec 6, 2020 at 6:12 PM Benjamin Kaduk <[email-masked]> wrote:
> _______________________________________________
> IPsec mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/ipsec

---

From: Tobias Brunner <[email-masked]>
Date: Thu, 17 Dec 2020 10:39:14 +0100

> given as a single string.

I think it's the other way around.  The byte-separated values are all in
little-endian encoding and d_i and d_r are simply given as hex-encoded
numbers (in their natural big-endian encoding as you'd write a decimal
number).  So I think the test vectors are correct.

Regards,
Tobias

---

From: Jonathan Hammell <[email-masked]>
Date: Fri, 18 Dec 2020 15:08:53 -0500

> number).  So I think the test vectors are correct.

I suppose I didn't interpret it that way given the text before d_i and
d_r says "encoded in little-endian format" and there is no leading
"0x" to indicate an integer versus a string.  The test vectors in RFC
7748 are written similarly as a hex string without leading "0x" and
must be decoded as strings (with decodeLittleEndian or
decodeUCoordinate), rather than being interpreted as an integer.
Given the tight relationship with RFC 7748, if RFC 8031 uses the same
notation for the d_i and d_r values but must be interpreted
differently is grounds for an errata, in my opinion.  I suppose that
clarification of the text would be acceptable.

Best regards,
Jonathan