概要
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
雑感
得られたハッシュ値を文字列として扱ってはまりました。