概要
OAuth2.0の文脈にて、パブリッククライアントが構成要素に含まれる場合にはよくお世話になるPKCE(Proof Key for Code Exchange)のcode_challengeの生成について記述します。
また、ここではcode_challenge_method
がS256
の時のことのみを考えます。
OAuth2.0の話や、PKCEの効用などは述べません。
code_challenge生成方法
RFC7636によると、code_challengeの生成方法は以下のように定義されています。
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
RFCにて、code_challenge_method
がS256
の時の具体例として、
code_verifier
がdBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
のときには、
code_challenge
はE9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
になる
とあるので、この例について説明していきます。
code_verifierをSHA256でハッシュ値にする
前提としてcode_verifier
はアルファベット
、数字
、-
、.
、_
、~
からなり、43~128文字から成ります。
ABNF for "code_verifier" is as follows.
code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39
code_verifier
のハッシュ値変換は、定義におけるSHA256(ASCII(code_verifier))
の部分で実施しています。
これをgit-bash上で実施すると以下のようになります。
$ echo -n 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' | shasum -a 256
13d31e961a1ad8ec2f16b10c4c982e0876a878ad6df144566ee1894acb70f9c3 *-
13D31E961A1AD8EC2F16B10C4C982E0876A878AD6DF144566EE1894ACB70F9C3
というハッシュ値が得られたことがわかります。
得られたハッシュ値をBASE64エンコードする
上記で得られたハッシュ値をBASE64エンコードするのですが、この値は16進数で表記されたものとして扱わなければいけません。
つまり、以下コマンドのように上記ハッシュ値を文字列としてBASE64エンコードしても、望む値は得られません。
$ echo -n '13D31E961A1AD8EC2F16B10C4C982E0876A878AD6DF144566EE1894ACB70F9C3' | base64
MTNEMzFFOTYxQTFBRDhFQzJGMTZCMTBDNEM5ODJFMDg3NkE4NzhBRDZERjE0NDU2NkVFMTg5NEFD
QjcwRjlDMw==
代わりに、xxdコマンドを使って値を16進数表記された文字列としてみると、期待する結果に近い値が取得できます。(下記、WSLで実行。git-bashにxxdコマンドがないため)
nannany@MyComputer:/mnt/c/WINDOWS/system32$ echo "13D31E961A1AD8EC2F16B10C4C982E0876A878AD6DF144566EE1894ACB70F9C3" | xxd -r -p | base64
E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw+cM=
得られたE9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw+cM=
をURLとして使える値にするために、
- パディングの
=
を削除 -
+
を-
に変換 -
/
を_
に変換
します。
その結果、期待したcode_challenge
を取得することができます。
nannany@MyComputer:/mnt/c/WINDOWS/system32$ echo "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw+cM=" | sed -e 's/=//g' | sed -e 's/+/-/g' | sed -e 's/\//_/g' | xargs -I {} test "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" == {} ; echo $?
0
雑感
得られたハッシュ値を文字列として扱ってはまりました。