アップルの痛みと証明書

経験豊富なios開発者であるBobに会って、Aliceはそれほど経験のないテスターです。 それは金曜日の夕方でした。 ボブはバグを修正しました。彼のデバイスでテストしたようです。 次に、ボブはすでに自動化に磨かれたコマンドを実行します。



git checkout develop git merge bug_fix_#999 git checkout master && git merge develop --no-ff .... git push ....
      
      







サーバーをプッシュすると、jenkins / teamcity / travisがトリガーされ、ビルドが開始されます。 同時に、ボブはアリスに手紙を書いて、すぐに家に帰る予定であり、週末が近づいているので、もちろんアプリがアリスの手動テストに合格すれば、さらに数日間勝つためにアプリを今日のアプリストアに上げたいと考えています。



ボブのアプリケーションはごく普通です。数百のコンパイルされたクラスファイル、数十のココアポッドの依存関係、たくさんのストーリーボード-ボブは自分の時間と同僚の時間を大切にしているので、コードにUIを記述しません。 ボブは、サーバー上のクリーンスタートからのアプリケーションが、アリスのテストに進む開発バージョンでは4分で組み立てられ、実稼働バージョンでは同じかそれ以上であることを知っています。 また、ボブは、アセンブリ全体が完了するのを約10分待ってから、テストを開始できることをアリスに伝えることも知っています。 ボブは責任者であるため、プッシュから10分後に、ビルドのステータスを確認します。サーバーは独自のルール、法律、および奇妙な並列世界であることがわかっているためです。



金曜日、夕方、ボブは待望の週末からわずか10分で、その後バトンをアリスに渡します。 ボブはbobcompany.ci/dashboardサファリにで行き、アプリケーションの前で赤信号が見え、ボブの目が暗くなり、失望に制限はありませんでした。 ボブはshow moreを押して、エラーが発生しました。



 Code Sign error: No codesigning identities found: No codesigning identities (ie certificate and private key pairs) that match the provisioning profile specified in your build settings (“com.company.bob”) were found.
      
      







その後、ボブの神経は完全に失われます。











*エラーについて簡単に説明すると、存在しない証明書でアプリケーションに署名しようとすると表示されます。存在しないか、マシンにインストールされていないか、同じバンドルの同じアカウントの最新バージョンの証明書にmobileprovisionがインストールされています。



そして最も厄介なのは、このエラーは開発バージョンの次に起動されるビルドの実稼働バージョンのみであり、最初にxcodeは依存関係(ココアポッド)をコンパイルし、その後に署名の有効性をチェックした後、つまりメインアプリケーションをビルドしたときのみです。 したがって、エラーはアセンブリプロセスの後半で発生するため、最初の6〜7分が無駄になり、ボブはさらに動揺します。



開発者Bobはこの問題に遭遇したのは初めてではありません。彼はios開発者のチームがいくつかある大企業で働いており、複数の人に対して1つのAppleアカウントを使用して開発するのが通常です。 はい、ボブはXcodeプラグインhttps://github.com/neonichu/FixCodeについて知っていますが、結局のところ、すべての人にそれを強制することを強制しないでください。開発者は優しい生き物です。そのような。



ボブはすべてに疲れていたので、10分前に家に帰るのを忘れていましたが、代わりに、ボブはピザを注文し、すでにパックしたMacbookを発見し、コーヒーを注ぎ、管理者にサーバーへのアクセスを許可し、ssh経由で接続し、見つけ始めます正確に問題とは何か、どのように解決できるか。



いいでしょう まず、ボブは一般にどの証明書がマシン上にあるかをチェックします。



 security find-identity -v login.keychain
      
      







どんな問題



  1) 40948A3CA3527F580B9ECB2131DE6B1938FB3D7C "iPhone Developer: Mike ... (KSDA3C3QF2)" 2) 0279CB81AEAD8CE015282DD1FA76CE520A815C4D "iPhone Developer: Bob .. (4WT74HLM2M)" 3) 79A2544B1A63C3F9D3DA3FFAB199FEAADB7EC306 "iPhone Developer: Alica ... (VJ53F2J4EK)" .... 24 valid identities found
      
      







したがって、少なくともサーバーでデフォルトで使用されるキーチェーンには、24の証明書があります。 Bobは、すべてのmobileprovisionファイルが1つの特定の証明書で作成されることを知っています。 ビルドが失敗したmobileprovisionファイルが作成された証明書を見つけ、証明書に何が起こったのかを理解する必要があります。 一般に、mobileprovisionファイルが証明書にどのように関連付けられているかを理解する必要があります。 ボブは、アプリケーションの開発バージョンがアセンブルされていることを知っているため、サーバーはこの証明書を確実に持っているので、mobileprovisionファイルとの関係を理解する必要があります。 これを行うには、Bobはmobileprovisionファイルと証明書情報を見つけて、それらの間の通信を探し始める必要があります。



バンドルごとにmobileprovisionファイルを探しています(バンドルがワイルドカードの場合、他の条件で検索できます)。



 cd ~/Library/MobileDevice/Provisioning Profiles find . -name "*.mobileprovision" -type f -exec grep -H -n -a {} -e "com\.company\.bob" \;
      
      







OK、ファイルが見つかりました:



 ./f98a06f3-21c2-4de0-975f-5df74197c731.mobileprovision:30: <string>4HUHB9J47M.com.company.bob</string>
      
      







バンドルには、ファイルに4HUHB9J47Mプレフィックスが付いています。 以前に受信した証明書のリストから、この値に一致するものはありません。 したがって、Bobはdeveloper.apple.comにアクセスして、このmobileprovisionファイルが作成されたアカウントを探す必要があります。 突く方法を使用して、彼はこれがマイクの証明書であることを見つけます:



 2) 40948A3CA3527F580B9ECB2131DE6B1938FB3D7C "iPhone Developer: Mike .. (KSDA3C3QF2)"
      
      







素晴らしい、今、私たちは一緒に働くものを持っています。 ボブは暗号解読者でもセキュリティ再販業者でもありませんが、グーグルは優秀なので、証明書から必要な情報を取得する方法を簡単に見つけました。



データを.pemファイルにプルします。



 security find-certificate -p -c "iPhone Developer: Mike .. (KSDA3C3QF2)" > cert.pem
      
      







ファイルでは、次のものを取得します。



 -----BEGIN CERTIFICATE----- MIIFnjCCBIagAwIBAgIIN8GwnYhLQ/kwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw ... .... ..... lD+ocFo6+mab/Ph6mTJOZkZu+hnqhzbTD9Q9dXKWkeXAwTqaESNfnhnuOdfCX3vu YAz0Hb46G9fkLa5lHjVydbtms685C+uz9Ss4GNRfji1cz5KyblAQAAsqQBUiCwnb z34= -----END CERTIFICATE-----
      
      







判明したように、証明書に関する情報はこのファイルから読み取ることができます。最も興味深いものを取得してみましょう。



 openssl x509 -noout -fingerprint -in cert.pem
      
      







それは私たちに与えます:



 SHA1 Fingerprint=40:94:8A:3C:A3:52:7F:58:0B:9E:CB:21:31:DE:6B:19:38:FB:3D:7C
      
      







コロンを削除すると、40948A3CA3527F580B9ECB2131DE6B1938FB3D7Cが得られます。これは、Mikeの証明書の単なるsha1であり、キーチェーンUIで確認できます。







有効期限が切れた証明書のバリデーターを作成する必要がある場合は、証明書の有効期間も取得できます。



 openssl x509 -noout -startdate -in cert.pem // Feb 27 07:13:41 2016 GMT openssl x509 -noout -enddate -in cert.pem // Feb 26 07:13:41 2017 GMT
      
      







キーチェーンでも同じことがわかります。







一般に、証明書ですべてが明確になります。 「どうすればmobileprovisionファイルに添付できますか?」と好奇心Bob盛なボブは考えます。 最初にmobileprovisionファイルを詳しく見てみましょう。







 security cms -D -i f98a06f3-21c2-4de0-975f-5df74197c731.mobileprovision
      
      







出力は、 データフィールドに関する興味深い情報を提供します



 <data> MIIFnjCCBIagAwIBAgIIN8GwnYhLQ/kwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1 ... ... YAz0Hb46G9fkLa5lHjVydbtms685C+uz9Ss4GNRfji1cz5KyblAQAAsqQBUiCwnb z34= </data>
      
      







どこかで、以前に受信した.pemファイルの内容と同様に、ボブはすでにこれを見ています。



 -----BEGIN CERTIFICATE----- MIIFnjCCBIagAwIBAgIIN8GwnYhLQ/kwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw ... .... ..... lD+ocFo6+mab/Ph6mTJOZkZu+hnqhzbTD9Q9dXKWkeXAwTqaESNfnhnuOdfCX3vu YAz0Hb46G9fkLa5lHjVydbtms685C+uz9Ss4GNRfji1cz5KyblAQAAsqQBUiCwnb z34= -----END CERTIFICATE-----
      
      











その後、ボブは、ここで彼女が証明書のmobileprovisionファイルのリーダーであることに気付きました。



合計で、mobileprovisionファイルを取得し、そこからデータフィールドの値を抽出し、すべての有効な証明書を実行して、.pem表現のデータと比較する必要があります。 ボブはすぐに小さなスクリプトを投げ、それをバックエンドから同僚に引き渡して、iosプロジェクトの各ビルドの前に同僚がそれを起動できるようにしました。 スクリプトは非常に簡単に起動されます。



 ruby cert_checker.rb f98a06f3-21c2-4de0-975f-5df74197c731.mobileprovision
      
      







ルビースクリプト
 require 'active_support/core_ext/hash' return if ARGV.empty? xmlString = `security cms -D -i #{ARGV.first}` data = Hash.from_xml(xmlString) #   data  mobileprovision provision_cert_data = data['plist']['dict']['array'].map { |e| e['data'] }.compact.first #          .pem  certs = `security find-identity -v login.keychain | grep -o "\\".*\\""`.split("\n").map { |e| e[1..-2] } pems = certs.map { |e| `security find-certificate -p -c "#{e}"`.split("\n")[1..-2].join('') } dict = Hash[pems.zip(certs)] #  mobileprovision data  .pem  ,  ,     mobileprovision, #   ,       if dict.keys.keep_if { |e| e == provision_cert_data }.empty? puts "Have no certificate for file #{ARGV.first}" else puts "Your mobileprovision issued for #{dict[provision_cert_data]}" end
      
      









証明書に問題がある場合、開発者はすぐにサーバーからフィードバックを取得できます。 一般的に、問題が解決するまで無駄にアセンブリを実行しないでください。



All Articles