<div dir="ltr"><div dir="ltr">Hi Davide and Junxiao,<div><br></div><div>Thank you for your comments. I just pushed updates.</div><div><br></div><div>* All strings are specified as UTF 8 encoded</div><div>* I made a separate section 2.3.3 to clarify the use of HKDF in NDNCERT</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Apr 13, 2020 at 12:28 PM Davide Pesavento <<a href="mailto:davidepesa@gmail.com">davidepesa@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Mon, Apr 13, 2020 at 8:18 AM Junxiao Shi via Nfd-dev<br>
<<a href="mailto:nfd-dev@lists.cs.ucla.edu" target="_blank">nfd-dev@lists.cs.ucla.edu</a>> wrote:<br>
><br>
> Hi Zhiyi<br>
><br>
> I'm trying to implement the protocol in NDNts. I've pasted my implementation of the crypto operations at the end of this message.<br>
> I have unit-tested these operations and they seem to be working. Since Node.js implements crypto via OpenSSL, this implies OpenSSL has sufficient primitives for crypto needed by NDNCERT.<br>
><br>
> I noticed some more issues in the protocol.<br>
><br>
><br>
> Several steps specify the use of signed Interest.<br>
> They should also specify which uniqueness assurance fields are required in the SignatureInfo: SignatureNonce, SignatureTime, SignatureSeqNum.<br></blockquote><div><br></div><div>Addressed. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
><br>
> Several steps specify MustBeFresh in Interest, but lacks FreshnessPeriod in Data. A Data without FreshnessPeriod cannot satisfy an Interest with MustBeFresh.<br></blockquote><div><br></div><div>Addressed.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> Given signed Interests are unique, it's unnecessary to include MustBeFresh.<br></blockquote><div><br></div><div>Let's still keep it.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
><br>
> Several TLVs are specified as *OCTET in ABNF, but text says "human readable string".<br>
> It also needs to specify what codec to use, such as UTF-8. If you want to restrict to ASCII instead, specify as *CHAR.<br>
<br>
I would NOT recommend to restrict ourselves to ASCII, it's 2020...<br>
<br>
> CA profile packet should have FinalBlockId (set to the same as last name component), so that it is compatible with segmentation convention.<br></blockquote><div><br></div><div>Added.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
><br>
> NEW response uses "challenge" TLV-TYPE, but it lacks number assignment.<br></blockquote><div><br></div><div>Fixed.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
><br>
> The AES-GCM session key is established by ECDH followed by HKDF.<br>
> WebCrypto cannot directly derive the HKDF key from ECDH. Instead, the workflow is:<br>
><br>
> derive bits from ECDH<br>
> import bits as HKDF key<br></blockquote><div><br></div><div>I assume the bits are used as HKDF IKM as defined in <a href="https://tools.ietf.org/html/rfc5869#section-2.2">https://tools.ietf.org/html/rfc5869#section-2.2</a>.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> derive AES-GCM key from HKDF key<br>
><br>
> The protocol specifies that the AES-GCM key is 128 bits. However, it does not specify how many bits go into the HKDF key.<br>
> Given ECDH on P-256 curve can establish a shared secret of 256 bits, I'd recommend specifying 256 bits.<br>
<br>
I'm not sure why this needs to be specified. The ECDH shared secret is<br>
normally the X coordinate of the calculated point, i.e. 32 bytes with<br>
NIST P-256. By saying that one must run HKDF with the ECDH shared<br>
secret as input, it's pretty obvious that you use the entire secret,<br>
nothing more, nothing less. I don't think there's any ambiguity here.<br>
<br>
><br>
><br>
> In PROBE/CHALLENGE request, parameter-value is specified as a string.<br>
> Some probe methods and challenges may natively use binary information. Thus, this field could be defined as binary instead.<br></blockquote><div><br></div><div>Addressed.</div><div><br></div><div>Best,</div><div>Zhiyi</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> parameter-key could stay as string, and defined as *CHAR if restricted to ASCII. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
><br>
><br>
> Yours, Junxiao<br>
><br>
><br>
><br>
> const ECDH_PARAMS: EcKeyGenParams & EcKeyImportParams = {<br>
>   name: "ECDH",<br>
>   namedCurve: "P-256",<br>
> };<br>
><br>
> export async function generateEcdhKey(): Promise<CryptoKeyPair> {<br>
>   return crypto.subtle.generateKey(ECDH_PARAMS, false, ["deriveBits"]);<br>
> }<br>
><br>
> export async function importEcdhPub(raw: Uint8Array): Promise<CryptoKey> {<br>
>   return crypto.subtle.importKey("raw", raw, ECDH_PARAMS, true, []);<br>
> }<br>
><br>
> export async function exportEcdhPub(key: CryptoKey): Promise<Uint8Array> {<br>
>   const raw = await crypto.subtle.exportKey("raw", key);<br>
>   return new Uint8Array(raw);<br>
> }<br>
><br>
> export async function makeSessionKey(<br>
>     ecdhPvt: CryptoKey,<br>
>     ecdhPub: CryptoKey,<br>
>     salt: Uint8Array,<br>
>     requestId: Uint8Array,<br>
> ): Promise<CryptoKey> {<br>
>   const hkdfBits = await crypto.subtle.deriveBits({ name: "ECDH", public: ecdhPub }, ecdhPvt, 256);<br>
>   const hkdfKey = await crypto.subtle.importKey("raw", hkdfBits, "HKDF", false, ["deriveKey"]);<br>
>   return crypto.subtle.deriveKey(<br>
>     {<br>
>       name: "HKDF",<br>
>       salt,<br>
>       info: requestId,<br>
>       hash: "SHA-256",<br>
>     } as any,<br>
>     hkdfKey,<br>
>     {<br>
>       name: "AES-GCM",<br>
>       length: 128,<br>
>     },<br>
>     false,<br>
>     ["encrypt", "decrypt"],<br>
>   );<br>
> }<br>
><br>
> export interface Encrypted {<br>
>   iv: Uint8Array;<br>
>   ciphertext: Uint8Array;<br>
> }<br>
><br>
> export async function sessionEncrypt(key: CryptoKey, plaintext: Uint8Array): Promise<Encrypted> {<br>
>   const iv = crypto.getRandomValues(new Uint8Array(12));<br>
>   const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);<br>
>   return { iv, ciphertext: new Uint8Array(ciphertext) };<br>
> }<br>
><br>
> export async function sessionDecrypt(key: CryptoKey, { iv, ciphertext }: Encrypted): Promise<Uint8Array> {<br>
>   const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext);<br>
>   return new Uint8Array(plaintext);<br>
> }<br>
><br>
> _______________________________________________<br>
> Nfd-dev mailing list<br>
> <a href="mailto:Nfd-dev@lists.cs.ucla.edu" target="_blank">Nfd-dev@lists.cs.ucla.edu</a><br>
> <a href="http://www.lists.cs.ucla.edu/mailman/listinfo/nfd-dev" rel="noreferrer" target="_blank">http://www.lists.cs.ucla.edu/mailman/listinfo/nfd-dev</a><br>
</blockquote></div></div>