🔐

CentOS9でGooglePlayの購入レシートの署名検証が失敗する原因と対策

2024/02/16に公開

概要

RailsでGooglePlayのレシートの署名を検証しているコードがRocky Linux9.3(CentOS9)に環境を変更した際にエラーになってしまったので原因と対策をまとめた。

起きている事

  • GooglePlayは購入レシートの署名時のアルゴリズムにSHA1を使用している
  • RedHat9ではシステム全体の暗号化ポリシーが変更され、SHA1の署名の利用が制限された
    互換OSであるCentOS9、Rocky Linux9でも同様の変更が行われている
  • 上記の理由により該当環境でSHA1の署名の検証を行うと「EVP_DigestVerifyInit: invalid digest」の例外が発生する
  • 対応するにはシステム全体の暗号化ポリシーを変更し、SHA1を許可する必要がある。※sudo権限が必要

再現環境

  • Rocky Linux 9.3 (CentOS9, RedHat9でも同様)
  • OpenSSL 3.0.7
  • Rails 7.0.8
  • Ruby 3.3.0

※Rails, Rubyのバージョンは今回の話では関係ありませんが念のため記載

再現コード

※ライセンスキー、レシート、署名についてはさすがにそのまま載せられないのでご了承ください

def verify_receipt_signature(license_key, receipt, sinature)
  verifier = OpenSSL::PKey::RSA.new(Base64.decode64(license_key))
  erifier.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), receipt)
end

license_key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8...'
receipt = "{\"orderId\":\"GPA.3365-9902-0523-32280\",\"packageName\":\"your package name\",\"productId\":\"your ...}"
signature = 'Mv7+ADM63TbNP...'
puts verify_receipt_signature(license_key, receipt, sinature)

正常に動作する環境では特にエラーは起きないが、

verify_receipt_signature(license_key, receipt, signature)
# => true/false

再現環境ではこのような例外が発生する。

`verify': EVP_DigestVerifyInit: invalid digest (OpenSSL::PKey::PKeyError)

原因と対策

RedHat9(CentOS9互換OS含む)からシステム全体の暗号化ポリシーが変更され、SHA1の署名がデフォルトでは利用できないので署名の検証も当然エラーになる。
出典:8.2. システム全体の暗号化ポリシー Red Hat Enterprise Linux 9 | Red Hat Customer Portal

これを変更するにはupdate-crypto-policiesコマンドを使用する。
まずは現在のポリシーを確認。当然DEFAULTと表示されるが、CentOS8では同じDEFAULTでもSHA1の署名が使用できていた。

$ sudo update-crypto-policies --show
DEFAULT

セキュリティレベルは下がるが、GooglePlayがレシートをSHA1で署名して来る以上は対応しなければいけない。update-crypto-policiesでDEFAULT:SHA1をセットする事でエラーが発生しないようにできる。

$ sudo update-crypto-policies --set DEFAULT:SHA1
Setting system policy to DEFAULT:SHA1
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
$ sudo update-crypto-policies --show
DEFAULT:SHA1

springが起動している場合は、キャッシュされているためspringを停止してから再現コードを実行する必要がある。

Discussion