[Nfd-dev] Try NDNCERT (based on Interest-Data exchange) and get an NDN certificate today

Junxiao Shi shijunxiao at email.arizona.edu
Thu Nov 21 10:22:13 PST 2019


Hi Zhiyi

The following responses are made on this protocol revision:
https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.2/68dd20c6457ffb6d57aac3eb7e06f0497dd4053a


different assigned numbers
>> Some assigned numbers differ between protocol (left) and implementation
>> (right).
>> NEW vs _NEW
>> CHALLENGE vs _CHALLENGE
>> DOWNLOAD vs _DOWNLOAD
>> EncryptedPayload: 602 vs 630
>> InitialVector: 605 vs 632
>>
>
> Addressed in the latest protocol Wiki page.
>

Incomplete.

   - PROBE in section 2.1 vs _PROBE in section 2.3.1 examples
   - NEW in section 2.1 vs _NEW in section 2.3.2 examples
   - CHALLENGE in section 2.1 vs _CHALLENGE in section 2.3.3 examples
   - DOWNLOAD in section 2.1 vs _DOWNLOAD in section 2.3.4 examples



>
>
>>
>> nonstandard base64
>> The CA expects a nonstandard base64 encoding format: encoder must insert
>> a newline after every 64 bytes.
>> Either the implementation should remove this requirement, or the protocol
>> should specify this requirement.
>>
>
> Sorry, could you elaborate on this? I think previously Ashlesh and Alex
> met a similar problem before.
> Are you saying the ECDH key base64?
> I checked the code at CA server. I didn't add or require any newlines when
> parsing base64. I used the base64 API from ndn-cxx:
>
> ```
> uint8_t*
> ECDHState::deriveSecret(const std::string& peerKeyStr)
> {
>   namespace t = ndn::security::transform;
>
>   OBufferStream os;
>   t::bufferSource(peerKeyStr) >> t::base64Decode() >> t::streamSink(os);
>   auto result = os.buf();
>
>   return this->deriveSecret(result->data(), result->size());
> }
>  ```
> *TODO: *solve the problem in a later commit.
>

ndn::security::transform::base64Decode(true) handles PEM format (RFC 1421
<https://tools.ietf.org/html/rfc1421> section 4.3.2.4), which requires a
newline after every 64 octets. See
https://redmine.named-data.net/issues/3741#note-12 .
Normally, base64 means the format defined in RFC 4648 section 4
<https://tools.ietf.org/html/rfc4648#section-4>, which disallows any
newlines.
According to RFC 4648 section 3.1
<https://tools.ietf.org/html/rfc4648#section-3.1>,

   MIME [4] is often used as a reference for base 64 encoding.  However,
   MIME does not define "base 64" per se, but rather a "base 64 Content-
   Transfer-Encoding" for use within MIME.  As such, MIME enforces a
   limit on line length of base 64-encoded data to 76 characters.  MIME
   inherits the encoding from Privacy Enhanced Mail (PEM) [3], stating
   that it is "virtually identical"; however, PEM uses a line length of
   64 characters.  The MIME and PEM limits are both due to limits within
   SMTP.

   Implementations MUST NOT add line feeds to base-encoded data unless
   the specification referring to this document explicitly directs base
   encoders to add line feeds after a specific number of characters.

The reason for PEM to insert newlines is to fit within SMTP's line length
limit. This consideration does not apply to JSON. Therefore, the
recommendation is:

   - Define the protocol to use base64 format as specified in RFC 4648
   section 3.1 (you should cite the RFC section)
   - Decode base64 format using
   ndn::security::transform::base64Decode(false) .
   - Encode base64 format using
   ndn::security::transform::base64Encode(false) .



>
>> Signed Interest format mismatch
>> Protocol specifies Signed Interest format from NDN Packet Format v0.3.
>> The CA expects 2014 Signed Interest format.
>> Either one should change to match the other.
>>
>
> Addressed in the latest protocol Wiki page.
>

Incomplete. Example does not match protocol definition.


>
>
>>
>> NEW/CHALLENGE statue encoding
>> Protocol specifies "status" field of NEW response is encoded as a number.
>> CA implementation encodes it as a string.
>>
> "remaining-tries" and "remaining-time" fields have same problem.
>>
>
> Addressed in the latest protocol Wiki page.
>

OK.


>
>
>> reuse ECDH key
>> CA is reusing the same ECDH key for all requests. It should generate a
>> unique ECDH key for each request.
>>
>
> This is truly a problem.
> *TODO: *I will move ECDH state to each request state.
>

There's no need to save ECDH state on the CA.
CA can generate ECDH key pair while processing the NEW command and compute
the AES key.
The ECDH private key can be destroyed immediately, and the CA only needs to
save the AES key for later.


>
>
>>
>> ECDH salt encoding
>> Protocol does not specify how salt is encoded.
>> CA implementation generates 8 bytes of random value, interprets it as
>> uint64, and prints in decimal string.
>> Protocol does not specify which endianness is used in this conversion.
>>
>
> Addressed in the latest protocol Wiki page.
>

Protocol still does not specify the endianness to convert [8]uint8 into
uint64.
Also, why not use base64, like the other fields?


>
>>
>> ECDH info
>> Protocol does not specify what is used as "info" in ECDH.
>> CA implementation assumes F0F1F2F3F4F5F6F7F8F9.
>>
>
> Addressed in the latest protocol Wiki page.
>

According to RFC 5869 <https://tools.ietf.org/html/rfc5869>section 3.2, the
'info' field should contain application-specific information, such as user
identities.
Therefore, you can get better security by using the wire encoding of the
certificate as 'info' field.


>
>> hkdf crash
>> ECDHState::deriveSecret
>> <https://github.com/named-data/ndncert/blob/aae119aeb9b5387f2fd8f80c56ee8cbfe8c15988/src/crypto-support/crypto-helper.cpp#L170>
>> assumes ECDH_compute_key to return 0 on error, but it actually returns -1.
>> Thus, when I provide incorrect ECDH public key, ECDHState::deriveSecret
>> does not detect the error, but assigns -1 to the length field.
>> Consequently, CaModule::onNew passes secretLen=-1 to hkdf(), which then
>> segfaults.
>>
>
> *TODO: *I will solve the problem by correcting the comparison.
>
>
>>
>> AES 128 vs AES 256
>> Protocol specifies 128-bit AES, but CA expects 256-bit AES.
>>
>
> Addressed in the latest protocol Wiki page.
>

Using 256-bit AES compromises security property of the protocol, because
ECDH using P-256 curve can only give you 128-bit of entropy.
See
https://www.lists.cs.ucla.edu/pipermail/nfd-dev/2018-November/003459.html .


>
>>
>> AES mode
>> Protocol does not specify AES mode. It should say "AES-CBC".
>>
>
> Addressed in the latest protocol Wiki page.
>

OK.


>
>
>>
>> missing pin-code crash
>> After selecting "pin" challenge, the next CHALLENGE Interest payload
>> should have "pin-code" key.
>> When I misspell it as "pin", the CA crashes because it cannot find
>> "pin-code" key.
>>
>
> *TODO: *I will solve the problem by having a try block.
>

OK.


>
>
>>
>> negative remaining time
>> For some reason, CA gives me a negative remaining-time value after I
>> enter a wrong code.
>> (these are not original JSON, but console.log output, but nothing is
>> modified)
>>
>> *CHALLENGE request 0*
>> { 'selected-challenge': 'pin' }
>> *CHALLENGE response 0*
>> {
>>   status: '1',
>>   'challenge-status': 'need-code',
>>   'remaining-tries': '3',
>>   'remaining-time': '3600'
>> }
>> *CHALLENGE request 1, wrong code*
>> { 'selected-challenge': 'pin', 'pin-code': '855899' }
>> *CHALLENGE response 1*
>> {
>>   status: '1',
>>   'challenge-status': 'wrong-code',
>>   'remaining-tries': '2',
>>   'remaining-time': '-2046070806'
>> }
>> *CHALLENGE request 2*
>> { 'selected-challenge': 'pin', 'pin-code': '850899' }
>> *CHALLENGE response 2*
>> {
>>   status: '3',
>>   'challenge-status': 'success',
>>   'remaining-tries': '0',
>>   'remaining-time': '0',
>>   'certificate-id': '8930813521911288448'
>> }
>>
>
> *TODO: *I will solve the problem.
>

OK.


>
>
>>
>> Purpose of certificate-id
>> I wonder what's the purpose of "certificate-id" field? It's not needed in
>> DOWNLOAD or any other command.
>>
>
> It's not needed in any commands.
> The original purpose of certificate-id is to tell the client what's the
> expected certificate-id after the DOWNLOAD command.
> After the client fetches the cert, it can check whether the last component
> of cert is equal to certificate-id, though this is not implemented and may
> not have real sense.
> Yes, I think I could simply remove this.
>
> This has already been removed in the lastest Wiki page.
> *TODO: *I will remove this in the implementation soon.
>

The certificate-id information is useful, and the protocol can be further
simplified:

   - Instead of certificate-id, add a certificate-name field to the
   successful CHALLENGE response. It should contain the full name (i.e.
   including ImplicitDigestSha256Component) of the certificate Data packet.
   - The certificate-name needs to be encoded in base64 of the Name binary
   format. It cannot use URI encoding, because URI encoding of certain field
   (e.g. version and segment) is not defined in the packet format, and thus
   may not be supported by all nodes.
   - Eliminate DOWNLOAD command.
   - Client can retrieve the certificate by expressing an Interest with the
   certificate name.
   - Since the certificate-name field contains the full name, the client
   can rest assumed that the certificate is indeed issued for this request.


Yours, Junxiao
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.lists.cs.ucla.edu/pipermail/nfd-dev/attachments/20191121/dc4c3151/attachment-0001.html>


More information about the Nfd-dev mailing list