TLS 1.3 ID21に追従した。
- Add a per-ticket nonce so that each ticket is associated with a different PSK.
NewSessionTicket に ticket_nounce が増えた。
struct { uint32 ticket_lifetime; uint32 ticket_age_add; opaque ticket_nonce<1..255>; opaque ticket<1..2^16-1>; Extension extensions<0..2^16-2>; } NewSessionTicket;
ID 20 までは、key schedule でいうところの PSK の値は、resumption_master_secret そのものだった。ID 21 では、以下のように算出するようになった。
PSK = HKDF-Expand-Label(resumption_master_secret, "resumption", ticket_nonce, Hash.length)
セッションで複数回NewSessionTicketが発行される場合は、ticket_nounceはユニークな値でなければならない。それを守れば、チケットごとにユニークなPSKの値が生成される。ID 20の仕様に対する明らかな攻撃方法は発見されていないが、ID 21の方が直感的に安全だろうと思われている。
セッションで1回しかNewSessionTicketが発行されない場合は、固定の文字列でもよい。(空文字列も許容するよう使用を変更すべき?)
なお、ID 21の HKDF-Expand-Label は曖昧になってしまったので、そのまま実装すると他の実装とは通信できない。具体的には、HKDF-Expand-Label は以下のように定められている。
HKDF-Expand-Label(Secret, Label, HashValue, Length) = HKDF-Expand(Secret, HkdfLabel, Length) struct { uint16 length = Length; opaque label<7..255> = "tls13 " + Label; opaque hash_value<0..255> = HashValue; } HkdfLabel;
ID 20 までは、HashValue の部分は、本当にハッシュ値か空文字列しか取らなかった。空文字列は、特殊なハッシュ値だと解釈されていた。HashValue の長さと、HKDF-Expand-Label の出力の長さを表す Length は、たまたま一緒であった。
今回、ticket_nounce も取るようになったので、その前提が崩れたことを OpenSLL の担当者が発見した。OpenSSLでは、上記の仕様を以下のように解釈して、実装している。
HKDF-Expand-Label(Secret, Label, Value, OutputLength) = HKDF-Expand(Secret, HkdfLabel, OutputLength) struct { uint16 length = OutputLength; opaque label<7..255> = "tls13 " + Label; // フィールドの長さが先頭に付く opaque value<0..255> = Value; // フィールドの長さが先頭に付く } HkdfLabel;