GoogleのOAuthが署名方法ににRSA-SHA1を取り入れていることは前から知っていましたが、内容までは見ていなかったので、ここで確認しておきます。
というのも、OpenSocialのGadgetがmakeRequestでOAuth APIにアクセスする際に、RSA署名を利用するSNSもあるらしいということを聞いたからです。
- Consumerは自らのアプリを登録してConsumerKeyを受け取る際に、SPに自分の公開鍵を預ける
- OAuthの署名の際に、Consumerはbase_stringに自分の秘密鍵を用いて署名する
- SPは受け取ったリクエストの署名とbase_stringを公開鍵を用いて検証する
■ OAuth Core 1.0の仕様
http://oauth.net/core/1.0/#anchor19
The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in \[RFC3447\] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5.
It is assumed that the Consumer has provided its RSA public key in a verified way to the Service Provider, in a manner which is beyond the scope of this specification.
キーワード
- RSASSA-PKCS1-v1_5 signature algorithm
- SHA-1
- EMSA-PKCS1-v1_5
9.3.1. Generating Signature
The Signature Base String is signed using the Consumer’s RSA private key per \[RFC3447\] section 8.2.1,
where K is the Consumer’s RSA private key,
M the Signature Base String,
and S is the result signature octet string:S = RSASSA-PKCS1-V1_5-SIGN (K, M)
oauth_signature is set to S, first base64-encoded per \[RFC2045\] section 6.8, then URL-encoded per Parameter Encoding.
キーワード
- K : ConsumerのRSA Privete key
- M : Signature Base String
- S : RSASSA-PKCS1-V1_5-SIGNした結果
- 最初にbase64-encoded、それからURL-encodedしてパラメータにセット?
9.3.2. Verifying Signature
The Service Provider verifies the signature per \[RFC3447\] section 8.2.2,
where (n, e) is the Consumer’s RSA public key,
M is the Signature Base String,
and S is the octet string representation of the oauth_signature value:RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S)
キーワード
仕様はこうなっています。
が、正直よくわからないので、PHPライブラリの中身を見て、実装内容を確認します。
■ PHPライブラリ
PHPライブラリのうち、RSA署名に関するものは以下のファイルになります。
http://code.google.com/p/oauth-php/source/browse/trunk/library/signature_method/OAuthSignatureMethod_RSA_SHA1.php
- Private Key,Public Keyをfetchする関数は未定義
- signature(署名作成)、verify(署名検証)の2つが定義済み
初めに、signature(署名作成)のロジックをみてみます。
<?php /** * Calculate the signature using RSA-SHA1 * This function is copyright Andy Smith, 2008. * * @param OAuthRequest request * @param string base_string * @param string consumer_secret * @param string token_secret * @return string */ public function signature ( $request, $base_string, $consumer_secret, $token_secret ) { // Fetch the private key cert based on the request // Private Keyの取得(未実装) $cert = $this->fetch_private_cert($request); // Pull the private key ID from the certificate // Private KeyからPrivate Key IDを取得 $privatekeyid = openssl_get_privatekey($cert); // Sign using the key // 署名作成 $sig = false; $ok = openssl_sign($base_string, $sig, $privatekeyid); // Release the key resource // リソース解放 openssl_free_key($privatekeyid); // base64エンコード、URLエンコードする return $request->urlencode(base64_encode($sig)); } ?>
シンプル。
openssl_signについては、http://php.filearena.net/manual/ja/function.openssl-sign.phpを参照してください。
続いて、verify(署名検証)のロジックを見てみます。
<?php /** * Check if the request signature is the same as the one calculated for the request. * * @param OAuthRequest request * @param string base_string * @param string consumer_secret * @param string token_secret * @param string signature * @return string */ public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ) { // URLデコードし、base64デコードする $decoded_sig = base64_decode($request->urldecode($signature)); // Fetch the public key cert based on the request // Public Keyを取得 $cert = $this->fetch_public_cert($request); // Pull the public key ID from the certificate // Public Key IDを取得 $publickeyid = openssl_get_publickey($cert); // Check the computed signature against the one passed in the query // 署名を検証 $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); // Release the key resource openssl_free_key($publickeyid); return $ok == 1; } ?>
openssl_verifyについてはhttp://php.filearena.net/manual/ja/function.openssl-verify.phpを参照してください。
ロジックはそれほど難しくないことがわかりました。
■ 署名部分のサンプルコード
RSAペアを作成します。
$ openssl genrsa -out rsa_priv.pem 1024
$ openssl rsa -in rsa_priv.pem -out rsa_pub.pem -outform PEM -pubout
$ ls rsa_*.pem
rsa_priv.pem rsa_pub.pem
署名するだけのコードを書いてみる。
クラスファイルのRSA読み込むところは適当に実装してる。
<?php // signature test $request = "request"; $base_string = "testbasestring"; $consumer_secret = "consumersecret"; $token_secret = "tokenseccret"; $test_RSA = new OAuthSignatureMethod_RSA_SHA1(); $signature = $test_RSA->signature ( $request, $base_string, $consumer_secret, $token_secret ); $signature_invalid = "invalidsignature"; $result_success = $test_RSA->verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ); $result_invalid_signature = $test_RSA->verify ( $request, $base_string, $consumer_secret, $token_secret, $signature_invalid ); ?>
成功のときは、1,失敗のときは空。
■ まとめ
実装も簡単、管理も公開鍵だけなので、OAuthのSPになる際には、RSA-SHA1の実装をお勧めします。
GoogleはRSA-SHA1使えるので、OAuthのサンプルもそのうち書いてみます。