Apa yang membuat item rantai kunci unik (di iOS)?

104

Pertanyaan saya menyangkut gantungan kunci di iOS (iPhone, iPad, ...). Saya pikir (tapi saya tidak yakin) bahwa penerapan gantungan kunci di bawah Mac OS X menimbulkan pertanyaan yang sama dengan jawaban yang sama.


iOS menyediakan lima jenis (kelas) item rantai kunci. Anda harus memilih salah satu dari lima nilai kunci kSecClassuntuk menentukan jenis:

kSecClassGenericPassword  used to store a generic password
kSecClassInternetPassword used to store an internet password
kSecClassCertificate      used to store a certificate
kSecClassKey              used to store a kryptographic key
kSecClassIdentity         used to store an identity (certificate + private key)

Setelah sekian lama membaca dokumentasi apel, blog, dan entri forum, saya menemukan bahwa jenis item gantungan kunci kSecClassGenericPasswordmendapatkan keunikannya dari atribut kSecAttrAccessGroup, kSecAttrAccountdan kSecAttrService.

Jika ketiga atribut dalam permintaan 1 sama dengan permintaan 2, Anda akan menerima item rantai kunci kata sandi umum yang sama, terlepas dari atribut lainnya. Jika satu (atau dua atau semua) atribut ini mengubah nilainya, Anda akan mendapatkan item yang berbeda.

Namun kSecAttrServicehanya tersedia untuk item jenis kSecClassGenericPassword, sehingga tidak dapat menjadi bagian dari "kunci unik" item jenis lain, dan tampaknya tidak ada dokumentasi yang menunjukkan dengan jelas atribut mana yang secara unik menentukan item rantai kunci.

Kode contoh di kelas "KeychainItemWrapper" dari "GenericKeychain" menggunakan atribut kSecAttrGenericuntuk membuat item menjadi unik, tetapi ini adalah bug. Dua entri dalam contoh ini hanya disimpan sebagai dua entri berbeda, karena keduanya kSecAttrAccessGroupberbeda (satu memiliki kumpulan grup akses, yang lain membiarkannya gratis). Jika Anda mencoba menambahkan kata sandi kedua tanpa grup akses, menggunakan kata sandi Apple KeychainItemWrapper, Anda akan gagal.

Jadi, tolong jawab pertanyaan saya:

  • Apakah benar, bahwa kombinasi kSecAttrAccessGroup, kSecAttrAccountdan kSecAttrServicemerupakan "kunci unik" dari item rantai kunci yang kSecClass-nya kSecClassGenericPassword?
  • Atribut mana yang membuat item rantai kunci unik jika kSecClasstidak kSecClassGenericPassword?
Hubert Schölnast
sumber
1
Ada entri blog di sini tentang ini.
bobobobo

Jawaban:

179

Kunci utama adalah sebagai berikut (berasal dari file open source dari Apple, lihat Schema.m4 , KeySchema.m4 dan SecItem.cpp ):

  • Untuk item rantai kunci kelas kSecClassGenericPassword, kunci utamanya adalah kombinasi dari kSecAttrAccountdan kSecAttrService.
  • Untuk item keychain kelas kSecClassInternetPassword, kunci utama adalah kombinasi kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPortdan kSecAttrPath.
  • Untuk item rantai kunci kelas kSecClassCertificate, kunci utamanya adalah kombinasi dari kSecAttrCertificateType, kSecAttrIssuerdan kSecAttrSerialNumber.
  • Untuk item keychain kelas kSecClassKey, kunci utama adalah kombinasi kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrEffectiveKeySize, dan pencipta, mulai tanggal dan tanggal akhir yang tidak terpapar oleh SecItem belum.
  • Untuk item rantai kunci kelas kSecClassIdentitysaya belum menemukan info di bidang kunci utama di file sumber terbuka, tetapi karena identitas adalah kombinasi dari kunci pribadi dan sertifikat, saya menganggap kunci utama adalah kombinasi dari kunci utama bidang untuk kSecClassKeydan kSecClassCertificate.

Karena setiap item rantai kunci termasuk dalam grup akses rantai kunci, rasanya grup akses rantai kunci (bidang kSecAttrAccessGroup) adalah bidang yang ditambahkan ke semua kunci utama ini.

Tammo Freese
sumber
Kedengarannya jawaban yang sangat bagus! Terima kasih! Saya akan memeriksanya dan saya ingin menunggu satu atau dua hari untuk komentar tambahan dari pengguna lain, tetapi Anda adalah kandidat terbaik untuk +50 poin dari bounty.
Hubert Schölnast
3
Jawaban yang bagus! Saya bekerja selama beberapa hari untuk mengimplementasikan pembungkus Keychain umum untuk sertifikat dan kunci pribadi. Itu sangat berbeda dengan kode sampel Apple yang hanya menyimpan kredensial string (nama pengguna / kata sandi). Namun, saya menemukan bahwa ketika Anda menyetel kSecClasske kSecClassCertificateatau kSecClassKeyrantai kunci juga memeriksa apakah entri (the value) sudah disimpan. Ini mencegah penambahan sertifikat atau kunci yang sama dua kali. Juga jika Anda menentukan kSecAttrApplicationTagkunci yang berbeda (yang harus unik, berkenaan dengan posting di atas) itu akan gagal.
Chris
1
Mungkin membantu untuk menganggap kSecClassatribut sebagai nama tabel , dan nilai yang ditentukan di atas hanya sebagai primary keytabel masing-masing.
bobobobo
2
Apa semantik dari kSecAttrAccountdan kSecAttrService? - atau dapatkah programmer memilih semantik yang dia putuskan?
wcochran
1
kSecAttrServiceadalah untuk menyimpan layanan, kSecAttrAccountuntuk menyimpan nama akun. Anda dapat menyimpan berbagai hal di dalamnya, tetapi itu mungkin membingungkan.
Tammo Freese
9

Saya terkena bug beberapa hari yang lalu (di iOS 7.1) yang terkait dengan pertanyaan ini. Saya menggunakan SecItemCopyMatchinguntuk membaca kSecClassGenericPassworditem dan itu terus kembali errSecItemNotFound(-25300) meskipun kSecAttrAccessGroup, kSecAttrAccountdan kSecAttrServicesemuanya cocok dengan item di gantungan kunci.

Akhirnya saya menemukan bahwa kSecAttrAccessibleitu tidak cocok. Nilai di rantai kunci dipegang pdmn = dk ( kSecAttrAccessibleAlways), tetapi saya menggunakan kSecAttrAccessibleWhenUnlocked.

Tentu saja nilai ini tidak diperlukan di tempat pertama untuk SecItemCopyMatching, tetapi OSStatusbukan errSecParamatau errSecBadReqmelainkan hanya errSecItemNotFound(-25300) yang membuatnya agak sulit untuk ditemukan.

Untuk SecItemUpdatesaya telah mengalami masalah yang sama tetapi dalam metode ini bahkan menggunakan yang sama kSecAttrAccessibledalam queryparameter tidak bekerja. Hanya menghapus sepenuhnya atribut ini yang memperbaikinya.

Saya harap komentar ini akan menghemat beberapa momen debugging yang berharga bagi sebagian dari Anda.

izik lisbon
sumber
4

Jawaban yang diberikan oleh @Tammo Freese sepertinya benar (tapi tidak menyebut semua kunci utama). Saya sedang mencari beberapa bukti di dokumentasi. Akhirnya ketemu:

Dokumentasi Apple menyebutkan kunci utama untuk setiap kelas rahasia (kutipan di bawah):

Sistem menganggap item sebagai duplikat untuk rantai kunci tertentu ketika rantai kunci tersebut sudah memiliki item dari kelas yang sama dengan kumpulan kunci utama gabungan yang sama. Setiap kelas item rantai kunci memiliki kumpulan kunci utama yang berbeda, meskipun beberapa atribut digunakan secara umum di semua kelas. Secara khusus, jika berlaku, kSecAttrSynchronizable dan kSecAttrAccessGroup adalah bagian dari kumpulan kunci utama . Kunci utama tambahan per kelas tercantum di bawah ini:

  • Untuk kata sandi umum, kunci utama mencakup kSecAttrAccount dan kSecAttrService.
  • Untuk kata sandi internet, kunci utama termasuk kSecAttrAccount, kSecAttrSecurityDomain, kSecAttrServer, kSecAttrProtocol, kSecAttrAuthenticationType, kSecAttrPort, dan kSecAttrPath.
  • Untuk sertifikat, kunci utama mencakup kSecAttrCertificateType, kSecAttrIssuer, dan kSecAttrSerialNumber.
  • Untuk item kunci, kunci utama mencakup kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrApplicationTag, kSecAttrKeySizeInBits, dan kSecAttrEffectiveKeySize.
  • Untuk item identitas, yang merupakan sertifikat dan kunci pribadi yang digabungkan bersama, kunci utama sama dengan untuk sertifikat. Karena kunci pribadi dapat disertifikasi lebih dari sekali, keunikan sertifikat menentukan identitasnya.
Julian Król
sumber
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
pwc
setuju, meskipun dalam hal ini berarti menyalin seluruh tautan.
Julian Król
0

Berikut ini adalah informasi berguna lainnya tentang keunikan item rantai kunci, yang dapat ditemukan di bagian "Pastikan Kemampuan Pencarian" di halaman dokumen Apple ini .

Untuk dapat menemukan item tersebut nanti, Anda akan menggunakan pengetahuan Anda tentang atributnya. Dalam contoh ini, server dan akun adalah karakteristik pembeda item. Untuk atribut konstan (di sini, server), gunakan nilai yang sama selama pencarian. Sebaliknya, atribut akun bersifat dinamis, karena memiliki nilai yang diberikan oleh pengguna pada waktu proses. Selama aplikasi Anda tidak pernah menambahkan item serupa dengan atribut yang berbeda-beda (seperti kata sandi untuk akun berbeda di server yang sama), Anda dapat menghilangkan atribut dinamis ini sebagai parameter penelusuran dan sebagai gantinya mengambilnya bersama dengan item tersebut. Akibatnya, saat Anda mencari kata sandi, Anda juga mendapatkan nama pengguna yang sesuai.

Jika aplikasi Anda menambahkan item dengan atribut dinamis yang berbeda-beda, Anda memerlukan cara untuk memilih di antara mereka selama pengambilan. Salah satu opsinya adalah mencatat informasi tentang item dengan cara lain. Misalnya, jika Anda menyimpan catatan pengguna dalam model Data Inti, Anda menyimpan nama pengguna di sana setelah menggunakan layanan rantai kunci untuk menyimpan bidang kata sandi. Kemudian, Anda menggunakan nama pengguna yang diambil dari model data Anda untuk mengkondisikan pencarian kata sandi.

Dalam kasus lain, mungkin masuk akal untuk mengkarakterisasi item lebih lanjut dengan menambahkan lebih banyak atribut. Misalnya, Anda mungkin menyertakan kSecAttrLabelatribut dalam kueri penambahan asli, memberikan string yang menandai item untuk tujuan tertentu. Kemudian Anda akan dapat menggunakan atribut ini untuk mempersempit pencarian Anda nanti.

Item kelas kSecClassInternetPassworddigunakan dalam contoh ini, tetapi ada catatan yang mengatakan:

Layanan rantai kunci juga menawarkan kelas item kSecClassGenericPassword terkait. Kata sandi umum dalam banyak hal serupa dengan kata sandi Internet, tetapi tidak memiliki atribut tertentu yang khusus untuk akses jarak jauh (misalnya, mereka tidak memiliki atribut kSecAttrServer). Jika Anda tidak membutuhkan atribut tambahan ini, gunakan kata sandi umum.

Aleksandar
sumber