<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS簽名校驗那些事兒

          共 12032字,需瀏覽 25分鐘

           ·

          2021-10-28 16:10

          ????關(guān)注后回復 “進群” ,拉你進程序員交流群????
          作者丨梅花祿
          來源丨百度Geek說(ID:baidugeektalk)


          導讀:iOS簽名校驗機制是蘋果生態(tài)安全的基礎(chǔ),日常工作中無論是開發(fā)階段還是測試階段常常會遇到很多需要通過簽名機制解決的問題,了解iOS簽名機制的原理有助于提高我們解決相關(guān)問題的成本和效率。本文首先介紹數(shù)字簽名和證書的原理,之后會介紹蘋果開發(fā)者證書的生成安裝過程,最后對蘋果實現(xiàn)簽名校驗的流程及流程中涉及的關(guān)鍵信息進行介紹,希望能對大家有所幫助。


          全文9494字,預計閱讀時間24分鐘。


          背景


          iOS15 beta 版發(fā)布后,QA 同學需要測試新功能在iOS 15 系統(tǒng)下的功能穩(wěn)定性,但是通過公司流水線打出的企業(yè)包無法安裝在 iOS 15 系統(tǒng)的設(shè)備上,具體報錯見下圖:



          通過在控制臺查看安裝過程中的具體報錯信息,發(fā)現(xiàn)具體的IPA 包的簽名信息在iOS 15系統(tǒng)上已經(jīng)不再被支持了: The code signature version is no longer supported.詳細的控制臺報錯信息如下圖所示:



          也就是安裝失敗和IPA 的代碼簽名版本有關(guān),為此通過codesign命令查看流水線產(chǎn)出的IPA 的相關(guān)簽名信息,具體信息見下圖,其中CodeDirectory的版本為v=20400



          CodeDirectory直譯是代碼目錄,記錄的是將 Mach-O文件分頁后每頁的哈希值信息,除此之外還包含了資源文件的摘要信息、權(quán)限信息等,這些信息按照一定的格式組合在一起,而不同的 signature version 對應(yīng)這不同的信息種類、組合形式或計算算法。去年從iOS 14 beta2開始,蘋果系統(tǒng)采用一種更為安全的簽名格式,在其上運行使用舊簽名格式簽名的APP時會出警告彈窗。其官方介紹中提到 In a future release, the new format will become mandatory, and the system won’t launch apps with the old signature format.因此懷疑是簽名格式在 iOS 15 系統(tǒng)上進行了強制校驗,導致安裝失敗:



          在官方文檔中提到 If you signed your app on a Mac running macOS 10.14 or later, the app already has the new signature format.換句話說 macOS 系統(tǒng)的版本會影響到簽名的格式;  "For any value of v less than 20400, you’ll need to re-sign your app." 


          CodeDirectory version 的值小于 20400  時可以通過重簽名來解決簽名失效問題。而CodeDirectory v=20400 可以安裝在iOS 14 系統(tǒng)上,但是卻無法安裝在iOS 15 系統(tǒng)上。為了解決這個問題,采用重簽名的思路,在macOS 11.5.2macOS 12.0 Beta 版系統(tǒng)下分別對流水線 IPA 包重簽名后,均可以正常安裝在 iOS 15 系統(tǒng)上了。


          以上是 iOS 簽名校驗機制的一個體現(xiàn),日常開發(fā)及測試中,與上述 iOS 簽名校驗機制相關(guān)的事情還有很多比如修改系統(tǒng)時間后使得企業(yè)證書過期從而導致啟動崩潰等,在這里再和大家一起分享下有關(guān) iOS 證書與簽名校驗相關(guān)的一些信息。


          首先我們看幾個問題:


          • 什么是簽名校驗機制?

          對可執(zhí)行文件或腳本進行數(shù)字簽名,用來保證軟件在簽名后未被損害或者修改的措施;


          • 蘋果為什么要使用簽名校驗機制?

          Signing your app allows iOS to identify who signed your app and to verify that your app hasn’t been modified since you signed it. 

          即確定APP來源并防止外部攻擊,以實現(xiàn)蘋果對其生態(tài)的控制;


          • 蘋果如何實現(xiàn)簽名校驗?


          這是 iOS 簽名校驗機制的流程示意圖,在學習過程中,個人覺得理解清楚非對稱加密、數(shù)字簽名以及數(shù)字證書的原理對于理解整個簽名機制非常重要,因此在文章的開始會對加密與解密、數(shù)字簽名以及數(shù)字證書做一些說明,然后結(jié)合數(shù)字簽名和證書的原理,對蘋果創(chuàng)建開發(fā)者證書的流程以及 iOS 簽名校驗流程包括過程中涉及到一些關(guān)鍵信息進行說明:


          1. 加密與解密、數(shù)字簽名、證書在通信過程中各自的作用

          2. 解析蘋果開發(fā)者證書的生成安裝過程

          3. 蘋果實現(xiàn)簽名校驗的流程及關(guān)鍵信息


          一、加密與解密、數(shù)字簽名、證書在通信過程中各自的作用


          無論是從 AppStore 下載 App 安裝到手機上還是在Debug 階段通過Xcode 將 App 安裝到測試機上進行真機調(diào)試,其實都是一次將 App 包發(fā)送到手機沙盒中的一次通信過程,如何保證一次安全有效的通信呢?或者說在一次通信過程中可能面臨哪些安全問題呢?


          A向B發(fā)送的明文,可以被中間路由直接查看,泄密了 --- 被竊聽
          好事者C修改了A向B請求內(nèi)容,使得A發(fā)起了錯誤請求 --- 被篡改
          好事者C攔截并模擬A向B發(fā)起請求,讓B誤以為是A發(fā)起的 --- 被欺騙
          A向B發(fā)起了請求,但是A就是不承認發(fā)起了此次請求 --- 被否認


          1.1 防止被竊聽 - 加密與解密


          通信過程中是不好避免被第三方攔截的,但是我們可以做到即便被截獲,竊聽者仍然無法破譯有效的信息,這個過程可以通過加密來實現(xiàn)。


          目前加密算法主要有兩大類,對稱加密和非對稱加密:

          對稱加密的特點是加密和解密使用的同一個秘鑰,其特點是速度快,常用算法有: DES 、3DES 、AES ;

          非對稱加密的密鑰分為公鑰和私鑰,其最重要的特性是使用公鑰加密的信息,只能使用私鑰解密,而使用私鑰加密的信息,只能使用公鑰進行解密,最常用的算法有 RSA ;


          但是對稱加密的密鑰管理繁瑣且密鑰傳輸存在一定的安全隱患,而非對稱加密算法速度比較慢,尤其是對于加密數(shù)據(jù)較大的信息時耗時更加明顯。因此在實際使用過程中,最常使用的是混合加密方式:

          發(fā)送方:1.對信息(明文)采用DES 密鑰加密;2.使用RSA加密前面的DES 密鑰信息;然后將1和2步產(chǎn)生的信息進行整合后傳遞。



          接收方:接收到信息后:1.用RSA解密DES 密鑰信息;2.再用RSA解密獲取到的密鑰信息解密密文信息;最終就可以得到我們要的信息(明文)。

           


          1.3 防止否認 - 數(shù)字簽名


          因為公鑰是對外公開的,A可以使用公鑰加密信息計算摘要,B也可以使用公鑰加密信息計算摘要,也就是所有擁有公鑰的人都可能成為信息發(fā)送者,這就導致A發(fā)送消息后可以否認。前面我們有提到非對稱加密的特性:使用公鑰加密的信息,只能使用私鑰解密,而使用私鑰加密的信息,只能使用公鑰進行解密。公鑰是對外公開的,但是私鑰僅存在于密鑰對生成者自己手里,所以當在發(fā)送消息時使用發(fā)送者的私鑰加密信息,在接收端使用發(fā)送者的公鑰來解密信息,那么接收端就可以精確確認消息發(fā)送者了,也就解決了消息發(fā)送者否認發(fā)送的問題。使用發(fā)送者的私鑰對摘要進行加密,就形成了簽名,即數(shù)字簽名。


          我們來看下數(shù)字簽名是如何起作用的:


          總結(jié)下數(shù)字簽名的作用,主要有三點:1.可以確認消息的完整性;2.可以識別消息是否被篡改;3.可以防止消息發(fā)送者否認;


          但是我們不能忽視一點:數(shù)字簽名生效的前提:用于加密的公鑰必須屬于真正的接受者,用于解密的公鑰必須屬于真正的發(fā)送者。如果公鑰被偽造了或者說好事者冒充發(fā)送者去發(fā)送消息,單純依賴數(shù)字簽名是無法解決的;我們一起來看下公鑰被偽造時會發(fā)生什么:



          由上圖可以看到,如果公鑰在傳輸過程中被偽造了,那么后續(xù)相關(guān)的通信過程都是建立一個偽造的密鑰對間進行,從而導致這個通信過程不再安全。因此在驗證簽名之前,首先得先驗證公鑰的合法性。


          但是如何保證公鑰的合法性呢?

          根據(jù)上面的相關(guān)介紹,為了保證公鑰信息不被篡改和欺騙,那么最好的方式就是對公鑰進行數(shù)字簽名,但問題又來了,如何保證此次數(shù)字簽名驗證過程中公鑰的合法性呢?再來一次數(shù)字簽名嗎?這就陷入了一個雞生蛋蛋生雞的過程了,為了打破這個死循環(huán),人們創(chuàng)造了證書中心和數(shù)字證書。


          1.4.保證公鑰的合法性 - 數(shù)字證書


          循環(huán)進行數(shù)字簽名的原因是因為公鑰有可能被偽造,為此人們將一些具有公信力的組織或者政府部門作為證書中心,由證書中心使用自己的私鑰來對公鑰進行數(shù)字簽名。通俗理解證書中心就是那些能夠認定“公鑰確實屬于此人”并且能夠生成數(shù)字簽名的權(quán)威個人或者組織,簡稱CA。而由CA對公鑰等信息施加數(shù)字簽名后就生成了證書。


          我們一起看下數(shù)字證書是如何起作用的:



          消息接收者首先生成密鑰對,并將公鑰_B 及郵箱等信息在CA 認證機構(gòu)中進行注冊,認證機構(gòu)CA 用自己的私鑰_CA 公鑰_B 進行數(shù)字簽名,并生成證書;消息發(fā)送者A向認證機構(gòu)CA 請求證書,并通過認證機構(gòu)CA 公鑰_CA 驗證數(shù)字簽名,以驗證公鑰_B 的合法性。


          對此,我們對公鑰、私鑰、數(shù)字簽名、數(shù)字證書的概念及作用有了一個大概的回顧。下面我們從數(shù)字簽名及數(shù)字證書的生成流程角度來看下iOS 開發(fā)者證書的生成與安裝過程。


          二、蘋果開發(fā)者證書的生成與安裝


          -1.生成證書請求:鑰匙串訪問 -> 證書助理 -> 從證書頒發(fā)機構(gòu)請求證書 (可以理解為Mac 端創(chuàng)建非對稱加密密鑰對公鑰M 和 鑰M 的過程,使用私鑰M 來簽署生成CSR 文件,CSR 文件中包含開發(fā)者的信息和公鑰M 私鑰M 則存儲在Mac端本地)



          -2.登錄開發(fā)者平臺,將第一步生成的CertificateSigningRequest.certSigningRequest上傳至Developer生成證書。(CertificateSigningRequest.certSigningRequest可以理解為Mac生成的公鑰,上傳至開發(fā)者平臺可以為將公鑰M 在證書認證機構(gòu)CA進行注冊,并利用蘋果開發(fā)者中心的公鑰A 對Mac設(shè)備的公鑰進行簽名,生成開發(fā)者證書)



          - 3.Mac將證書下載到本地,雙擊安裝(在安裝過程中,鑰匙串keychain會將第一步生成的私鑰M 與第二步生成的Cer 證書關(guān)聯(lián)在一起:



          三、蘋果實現(xiàn)簽名校驗的流程及關(guān)鍵信息


          蘋果簽名校驗機制的作用是要保證每一個安裝到iOS 設(shè)備上的App 都是經(jīng)過蘋果官方授權(quán)的。為了實現(xiàn)上述效果,蘋果采取的方案是雙重簽名,其大概流程可以參見下圖:


          > 1.首先在Mac端生成一對密鑰對(公鑰M和私鑰M),蘋果也會生成一對秘鑰對(公鑰A和私鑰A),其中公鑰A預置在iOS設(shè)備上,私鑰A放在蘋果服務(wù)器中;

          > 2.開發(fā)者通過開發(fā)者后臺將公鑰M上傳至蘋果服務(wù)器,蘋果服務(wù)器使用私鑰A對公鑰M進行簽名生成證書,開發(fā)者下載該證書并安裝在Mac中。安裝過程中會將證書與私鑰M進行關(guān)聯(lián)。

          > 3.在開發(fā)過程中,會使用私鑰M對APP進行簽名,同時會將證書也打包進APP中。

          > 4.在安裝過程中,iOS系統(tǒng)首先會使用預置的公鑰A對證書進行驗證,得到公鑰M(驗證成功,即說明證書是經(jīng)過蘋果私鑰簽名過的,根據(jù)前面的講解我們知道這樣就說明是經(jīng)過蘋果認證的了),然后使用公鑰M對簽名進行驗證,驗證成功后才能將APP安裝在設(shè)備中。


          那是不是只要擁有一個經(jīng)過蘋果認證的開發(fā)者證書,就可以將任意App 安裝在任意測試機上呢?顯然這是蘋果生態(tài)所不允許的。那蘋果是通過什么方式實現(xiàn)設(shè)備限制的呢?而且,在團隊開發(fā)中,也并不是所有人都去生成開發(fā)者證書,那又是通過什么方式實現(xiàn)團隊授權(quán)的呢?以及在蘋果開發(fā)者中心中配置的BundleID 、Capabilities 、Devices 等信息在簽名機制中又扮演著什么樣的作用呢?


          3.1 關(guān)P12 - 團隊協(xié)作開發(fā)

          在上面的簽名過程中,我們看到開發(fā)者在對App 進行簽名過程中,主要用到兩個信息:私鑰M 和證書,因此只需要將這兩個信息提供給團隊中的其它成員。在證書安裝過程我們了解中,鑰匙串會將證書與Mac生成的私鑰M 進行關(guān)聯(lián)并存儲為鑰匙串中的一項,鑰匙串支持將其導出為p12  文件,然后我們將p12 文件提供給團隊成員安裝就可以了。



          3.2 關(guān)于Entitlements - 權(quán)限管控


          Xcode 在編譯打包時會自動執(zhí)行/usr/bin/codesign 命令進行代碼簽名,以下是簽名的詳細信息:



          在簽名時通過--sign 指定了證書信息,那么--entitlements 配置的是什么信息呢?

          entitlements鏈接:

          (https://developer.apple.com/library/archive/technotes/tn2415/_index.html)


          An Entitlement can be thought of as the string written into an app's signature that allows a specific capability or opts the app into a specific service. The operating system (OS) checks these strings before allowing an app access to certain features. For example, an app must have the iCloud entitlement before it is allowed to access iCloud APIs at runtime.


          簡單來說entitlements其實就是iOS 沙盒環(huán)境的配置文件,蘋果通過entitlements文件來管控一個App 所能使用的服務(wù)和權(quán)限。Sandbox(沙盒)是iOS 安全體系中很重要的一環(huán),沙盒不僅僅使App 間相互獨立,同時也對每個App 可操作的行為進行了管控,比如可以使用哪些敏感的系統(tǒng)能力(Push、Sign in with apple等)等。Xcode 會默認生成一個包含有Team ID 信息和App ID 信息的權(quán)限聲明,如果在Xcode  Signing&Capabilities中開啟了相關(guān)權(quán)限,那么會顯式的生成一個后綴名為.entitlements的配置文件,里面包含了相關(guān)權(quán)限信息的說明。在--entitlements 選項后面的文件是在.entitlements的配置文件基礎(chǔ)上增加了默認配置后的信息。在Xcode 簽名時,會將該權(quán)限信息文件嵌入到二進制代碼中,作為被簽名內(nèi)容的一部分,由代碼簽名保證其不會被篡改。  


          可通過 security cms -D -i /path/to/iOSTest.mobileprovision 來檢查本地的 Provisioning Profile 是否包含所需要的權(quán)限。


          3.3 關(guān)于Provisioning profile


          Provisioning profile act as a link between the device and the developer account. During development, you choose which devices can run your app and which app services your app can access. A provisioning profile is downloaded from your developer account and embedded in the app bundle, and the entire bundle is code-signed.  


          Provisioning Profile 是一個由蘋果證書中心加密簽名的一個plist文件,包含有與之綁定的App ID、設(shè)備的UUID??????????????????列表、過期時間、TeamID、entilements等信息以及用于對應(yīng)用程序進行簽名的證書,是蘋果用來解決對設(shè)備授權(quán)以及管控APP敏感權(quán)限的解決方案。其在證書中心的配置頁面如下:



          在證書中心配置完App IDUnique Device Identifiers以及capabilities 等信息后,蘋果證書中心會將這些信息與證書一起使用蘋果的私鑰進行簽名,最后將簽名信息與配置信息、證書、簽名信息一起組成一個Provisioning Profile 文件。開發(fā)者將其下載并安裝,默認情況下Xcode 會自動幫助開發(fā)者進行管理。以下是Xcode中安裝的Provisioning Profile 信息:



          Mac編譯完一個App 后,會將Provisioning Profile 文件也打包進App 中,并將文件命名為embedded.mobileprovision。在App 安裝到iOS 設(shè)備上時,iOS 設(shè)備會通過預置的公鑰信息來驗證embedded.mobileprovision的簽名合法性,進而驗證證書中的簽名是否正確。


          確保了embedded.mobileprovision 里的數(shù)據(jù)都是蘋果授權(quán)以后,就可以使用其中的信息來校驗本次安裝的合法性,使用公鑰A驗證Mach-O 的簽名信息、驗證證書的簽名及有效期、驗證設(shè)備ID是否在設(shè)備列表中、Provisioning Profile 中的App ID是否與BundleID是否匹配等等;


          值得注意的一點是:設(shè)備列表只在Development證書下生效,因為Enterprise 、Distribution 證書本身就是要求可以任意安裝,所以不受設(shè)備列表的限制;過期時間只對DevelopmentEnterprise 證書生效,Distribution 證書下不受限制,這也是當Development、Enterprise 證書過期后會導致應(yīng)用無法安裝或無法啟動,而從App Store下載的應(yīng)用不會有時間限制。


          當然在開發(fā)者中心可以隨時對Provisioning Profile 進行修改,更新不會對已有Provisioning Profile 產(chǎn)生影響。


          3.4 關(guān)于可執(zhí)行文件與資源的簽名


          在編譯生成App 的過程中,Xcode 會通過鑰匙串找到與配置證書配對的私鑰M對二進制文件進行簽名,并將簽名信息嵌入到可執(zhí)行二進制文件中,用于在安裝時確認Mach-O 文件是否有被修改??赏ㄟ^MackOView 驗證:



          但是App 中不僅僅包含二進制文件,還包含一系列諸如圖片、音視頻文件等預置資源,因此通過單一的對二進制文件進行簽名不足以保證整個App 文件的完整性和有效性。在iOS 中,應(yīng)用程序使用遵循shallow application bundles結(jié)構(gòu)的目錄來存儲必要資源和數(shù)據(jù)信息,大致為:

          TestProject.app |用戶可見應(yīng)用程序

              Info.plist |文件,其中包含有關(guān)軟件包的信息

              TestProject |可執(zhí)行二進制

              Assets.car |圖標,顯示為用戶可見應(yīng)用程序

              Framework |任何可執(zhí)行文件使用的框架或動態(tài)庫

              AFNetworking.framework |iOS 軟件中常見框架示例


          以下是一個非常簡單的IPA包的包結(jié)構(gòu):



          可以看到為了保證可執(zhí)行文件及其在運行期間所依賴的數(shù)據(jù)和資源不被篡改,在實際生成的APP包中,會新生成一個_CodeSignature 目錄,在該目錄下包含一個名為CodeResources 文件,該文件為plist 類型的文件,里面包含了App 下除可執(zhí)行文件外其它文件的信息,key 通常為文件名,value 通常為其摘要信息。里面會有files files2 兩項,其中files保存的是每個文件的sha1的值,files2同時保存了sha1sha256,主要原因是sha1存在不安全性。_CodeSignature/CodeResources 文件的主要作用是記錄簽名后每個文件的哈希值,以在安裝時用來確保對應(yīng)的文件沒有被篡改過。


          3.5 簽名及校驗流程



          > 1.首先在Mac 端生成一對密鑰對(公鑰M和私鑰M),蘋果系統(tǒng)本身也會生成一對密鑰對(公鑰A和私鑰A),其中公鑰A預置在iOS 設(shè)備上,私鑰A放在蘋果服務(wù)器中;

          > 2.開發(fā)者將公鑰M整合在csr 文件中通過開發(fā)者后臺上傳至蘋果服務(wù)器,蘋果服務(wù)器使用私鑰A對公鑰M進行數(shù)字簽名生成證書;同時使用私鑰A將證書、AppID、entilements、設(shè)備UDIDs等信息加密生成Provisioning Profile 文件;對應(yīng)的開發(fā)者下載證書和Provisioning Profile 文件并安裝在Mac 中。安裝過程中會將證書與私鑰M進行關(guān)聯(lián),Xcode 默認會對Provisioning Profile 文件進行管理。

          > 3.在開發(fā)過程中,會使用私鑰M對App 進行簽名,同時會將Provisioning Profile 文件也打包進App 中即embedded.mobileprovision文件。

          > 4.當將iOS 設(shè)備與Xcode 連接并通過身份驗證后,Xcode 會將App 數(shù)據(jù)傳輸?shù)?span style="letter-spacing: 0.5px;color: rgb(30, 107, 184);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;background-color: rgba(27, 31, 35, 0.05);">iOS 設(shè)備中,iOS 設(shè)備此時并不會創(chuàng)建真正的沙盒環(huán)境來運行App ,而是會在一個臨時沙盒環(huán)境中來存放陸續(xù)收到的數(shù)據(jù),一旦全部接收完,iOS 系統(tǒng)首先會使用預置的公鑰A對embedded.mobileprovision文件的簽名進行驗證,已確認App 來源是否合法;來源合法性驗證通過后,便可使用公鑰M去驗證里面證書的簽名信息、驗證該設(shè)備ID是否在對應(yīng)UUID 列表中、以及APP中的權(quán)限開關(guān)配置是否和embedded.mobileprovision文件中配置的entilements信息相吻合等;同時會讀取_CodeSignature/CodeResources 中的信息對資源文件進行校驗。只有全部經(jīng)過驗證后,才會為App 創(chuàng)建真正的沙盒環(huán)境進行安裝。在啟動APP時,系統(tǒng)也會執(zhí)行相應(yīng)的啟動校驗,以防止安裝后進行的修改。


          參考文獻:

          1.https://developer.apple.com/documentation/xcode/using-the-latest-code-signature-format

          2.https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html

          3.https://pewpewthespells.com/blog/migrating_code_signing.html

          4.http://blog.cnbang.net/tech/3386/

          5.https://developer.apple.com/library/archive/recipes/ProvisioningPortal_Recipes/DownloadingaProvisioningProfile/DownloadingaProvisioningProfile.html

          6.https://developer.apple.com/library/archive/technotes/tn2415/_index.html

          7.https://developer.apple.com/library/archive/qa/qa1814/_index.html#//apple_ref/doc/uid/DTS40014030

          8.https://getupdraft.com/blog/ios-code-signing-development-and-distribution-prov

          9.https://abhimuralidharan.medium.com/what-is-a-provisioning-profile-in-ios-77987a7c54c2

          -End-


          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!


          點擊??卡片,關(guān)注后回復【面試題】即可獲取

          在看點這里好文分享給更多人↓↓

          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品后入 | 欧美成人在线视频观看 | 黄色视频Mic本 | 欧美乱伦网站 | 大香蕉视频在伊98 |