1 2 3 4 5 6 Previous Next 105 Replies
      Latest reply on Oct 3, 2016 2:30 AM by eskimo Go to original post
      • 45. Re: Keychain error -34018 (errSecMissingEntitlement)
        littledetails Level 1 Level 1 (0 points)

        Can confirm the -34018 error is still present in iOS 9.2.

        • 46. Re: Keychain error -34018 (errSecMissingEntitlement)
          rislam Level 1 Level 1 (0 points)

          Ditto, started seeing this today.

           

          result = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
          

           

          (lldb) p result

          (OSStatus) $1 = -34018

           

           

          • 47. Re: Keychain error -34018 (errSecMissingEntitlement)
            aarmstrong Level 1 Level 1 (0 points)

            Did you notice if this improved things? I moved my keychain access from '....aplicationDidFinishLaunching...' to the '...applicationDidBecomeActive..' but we are still seeing the issue; although it appears to be less often.

            • 48. Re: Keychain error -34018 (errSecMissingEntitlement)
              aarmstrong Level 1 Level 1 (0 points)

              Quinn,

               

              OK, I followed your advice and openned a defect; I hope Apple can find the root cause and provide an OS fix or at least a workaround on the code side.

              • 49. Re: Keychain error -34018 (errSecMissingEntitlement)
                Easter Egg Level 1 Level 1 (0 points)

                Don't hold your breath.....this bug has been in the OS for ages and no fix is in sight.

                 

                Only two options:

                • Either Apple has decided this is not worth fixing and is ignoring it -> we are screwed
                • Or Apple is trying but CAN'T fix this -> we are royally screwed

                 

                Our only course of action is to make as much noise as possible to attract Apple/Others/the Media's Attention and bring the issue to the spotlight to ensure Apple commits the appropriate resources to fixing this.

                 

                This is affecting at least a few major developers (I know Facebook/Parse runs into this issue), so we must unite to make our voices heard.

                 

                Everybody should file their own bugs about this so Apple understands it's affecting many of us. And then make as much noise as possible. Should we consider a petition to Tim?

                 

                Merry Christmas everyone. At least I know what I want front Santa this year....!

                • 50. Re: Keychain error -34018 (errSecMissingEntitlement)
                  mvayngrib Level 1 Level 1 (0 points)

                  same here, on SecItemCopyMatching, XCode 7.2, iOS 9.2, running attached to debugger

                   

                  you can see the code here: https://github.com/tradle/react-native-ecc

                   

                  SecItemAdd goes through: https://github.com/tradle/react-native-ecc/blob/master/ios/RNECC.m#L141

                  SecItemCopyMatching intermittently fails with the dreaded 34018: https://github.com/tradle/react-native-ecc/blob/master/ios/RNECC.m#L399

                   

                  if there's any other information i can provide to speed up the resolution of this bug, don't hesitate to ping me at mark@tradle.io

                  • 51. Re: Keychain error -34018 (errSecMissingEntitlement)
                    GoRoS Level 1 Level 1 (0 points)

                    I can confirm I have another case of this bug in official releases running iOS 9.2 on more than one device. In my case that scares a lot due to we trust on the KeyStore very sensitive and crucial information for the app.

                     

                    As a software engineer, It strongly draws my attention that this bug is still alive after some years bearing in mind its importance.

                    • 52. Re: Keychain error -34018 (errSecMissingEntitlement)
                      fritza Level 1 Level 1 (0 points)

                      Same here. iPhone 6, iOS 9.2 (13C75), using Alamofire and AlamofireImage. I’m working in Swift, with a Keychain struct I created myself.

                       

                      After three or four retrievals (it’s pretty consistent), SecItemCopyMatching returns -34018. (See Keychain.password(), below; the error hits at the call to SecItemCopyMatching().) Resetting the password during the run of the app does not help; killing and restarting it clears the error for another three or four cycles, which I don’t have to say is unacceptable. The stored password is still there; Keychain.password() returns it as expected. The bug manifests even if no other SecItem* call is made.

                       

                      (I see I don’t release returnPointer in that func; I’ll correct that in my own copy. I don’t think it should affect the bug, it’s just an 8-byte leak. I’m leaving the fix out of this listing to preserve my example.)

                       

                      I use the password by embedding a hash in the body of my transactions. (I use POSTs or PUTs, even in cases that would ordinarily use GETs.) I don’t claim this is what an experienced developer would do; I’m just describing the circumstances. All transactions are performed through Alamofire; this sometimes entails a loop of transactions such as the upload of a few images; the password is retrieved only once for each series.

                       

                      Quinn’s previous suggestion that this may be an entitlements or signing issue doesn’t seem to hold up here:

                       

                      • The app runs impeccably in the simulator (which says very little about signing).
                      • SecItemCopyMatching() does work a few times before failing. (Three times, I think — always the same number.)
                      • I’ve winnowed out some signing identities that might have conflicted; this came up because…
                      • … the forced codesign script phase (suggested elsewhere) complained it couldn’t disambiguate the identity CNs. Cutting the certificates down silenced that error but did not stop the -34018.
                      • I’ve copied and pasted among the bundle ID and keychain-sharing group entitlement.
                      • I’ve registered the bundle ID specifically with Apple (should not be necessary).
                      • I’ve forced the provisioning profile and signature.
                      • I’ve allowed Xcode to repair all the damage I did in those last few steps.

                       

                      I’m appending my Keychain struct for thoroughness. I DO NOT recommend it for use in others’ work. I have not qualified it as a product. Developers must be particularly on their guard about security practices, and I have no illusions about mine.

                       

                      //
                      //  Keychain.swift
                      //  Incident
                      //
                      //  Created by Fritz Anderson on 11/28/15.
                      //  Copyright © 2015 The University of Chicago. All rights reserved.
                      //
                      
                      import Foundation
                      import Security
                      import CommonCrypto
                      
                      func hashPassword(password: String) -> NSData {
                          let hashLength = 256/8
                          let stringData = password.dataUsingEncoding(NSUTF8StringEncoding)!
                          let digestBytes = UnsafeMutablePointer.alloc(hashLength)
                          CC_SHA256(stringData.bytes, UInt32(stringData.length), digestBytes)
                          return NSData(bytes: digestBytes, length: hashLength)
                      }
                      
                      extension NSData {
                          var hexString: String {
                              let contents = UnsafeBufferPointer(
                                  start: UnsafePointer(bytes),
                                  count: length)
                              return contents.reduce("") {
                                  $0 + String($1, radix: 16)
                              }
                          }
                      }
                      
                      func credentialsDictionary(user: String? = nil,
                          host: String? = nil) throws -> [String: AnyObject]
                      {
                          let userName = user ?? (DefaultsKeys.AccountName.value() as! String)
                          var retval: [String: AnyObject] = ["account" : userName]
                          
                          let hostName = host ?? Globals.HostName.value!
                          
                          var chain = Keychain(user: userName, host: hostName)
                          if let password = try chain.password() {
                              let hash = hashPassword(password).hexString
                              retval["password"] = hash
                          }
                          else {
                              throw KeychainError.NoPasswordDefined(user: userName, host: hostName)
                          }
                          return retval
                      }
                      
                      func credentialsJSONData(user: String? = nil,
                          host: String? = nil) throws -> NSData
                      {
                          let dict = try credentialsDictionary(user, host: host)
                          return try NSJSONSerialization.dataWithJSONObject(dict, options: [])
                      }
                      
                      public enum KeychainError : ErrorType {
                          case Duplicate
                          case OperationOnMissing
                          case NotAuthorized
                          case Parameter
                          case Generic(osError: Int)
                          case NoPasswordDefined(user: String, host: String)
                          
                          /// The `KeychainError` case matching an `OSStatus` value.
                          ///
                          /// - parameters:
                          ///     - status: the `OSStatus` to match
                          ///
                          /// - returns: Optional `KeychainError`: `nil` if the code was `noErr`; `.Generic` if it was not covered by any of the other cases; or one of those cases if it matches a recognized code. See the source for this `func` for details.
                          public static func fromOSStatus(status: OSStatus) -> KeychainError? {
                              switch status {
                              case noErr: return                  nil
                              case errSecDuplicateItem: return    .Duplicate
                              case errSecItemNotFound: return     .OperationOnMissing
                              case errSecAuthFailed: return       .NotAuthorized
                              case -50: return                    .Parameter
                              default: return                     .Generic(osError: Int(status))
                              }
                          }
                          
                          /// A description of the represented error, tagged with an optional context string.
                          ///
                          /// The optional context string is prepended to the returned description. Example, without a context:
                          ///
                          ///     "There was no such entry."
                          ///
                          /// If the context is "changing the password":
                          ///
                          ///     "While changing the password: There was no such entry."
                          ///
                          /// Notice that the context string is wrapped in "While _ : ". Adjust your phrasing accordingly.
                          ///
                          /// - parameters:
                          ///     - attempting: `nil` (the default) if there is to be no tag; otherwise a string to insert in the description.
                          ///
                          /// - returns: A description of the error, including the context string if one was supplied.
                          public func explain(attempting: String? = nil) -> String {
                              let circumstance: String
                              if let attempting = attempting {
                                  circumstance = "While \(attempting): "
                              }
                              else { circumstance = "" }
                              
                              let expansion: String
                              
                              switch self {
                              case .Duplicate: expansion =            "Another entry was already there."
                              case .OperationOnMissing: expansion =   "There was no such entry."
                              case .NotAuthorized: expansion =        "The operation was not authorized."
                              case .Parameter: expansion =            "An internal error (paramErr) occurred.\n\n"
                                  + "Please report this to me@example.com"
                              case let .Generic(osError): expansion =  "An unexpected error occurred (\(osError))."
                              case let .NoPasswordDefined(user: user, host: host):
                                  expansion = "No password was defined for \(user) on \(host)."
                              }
                              
                              return circumstance + expansion
                          }
                      }
                      
                      
                      /**
                       Convenient access to the system keychain.
                       
                       `struct Keychain` simplifies CRUD operations on the system
                       keychain by wrapping every search and initialization parameter
                       internally, where client code can’t see.
                       
                       There is no custom initializer; call `Keychain(user:,host:)`
                       
                       The client initializes the struct with username and host.
                       After that,
                       * `password()` retrieves the password, if the matching
                       record is in the keychain.
                       * `setPassword(_:)` creates or updates the keychain record.
                       * `delete()` removes the record.
                       
                       Getting or setting the password is always a mutation, because the underlying Security Framework calls set `osStatus`.
                       
                       - throws: Any of a number of `KeychainError`s.
                       The `enum` specifies the likeliest errors. Any other is thrown
                       as `KeychainError.Generic`; examine `osStatus` for the code.
                       */
                      
                      struct Keychain {
                          // MARK: Publicly-accessible data
                          
                          /// The login ID for the user, such as `criedel`.
                          let user:       String
                          
                          /// The name of the host for the user’s account, such as `www.example.com`.
                          let host:       String
                          
                          /// The error value (or `noErr`) from the last Keychain call.
                          var osStatus:   OSStatus = noErr
                          
                          init(user: String, host: String) {
                              self.user = user
                              self.host = host
                          }
                          
                          // MARK: Getter/setter for password
                          
                          /// The password for the user + host as stored in the keychain.
                          ///
                          /// The absence of the user + host, or a password for the combination,
                          /// is one of the expected outcomes; the function will return `nil`
                          /// in that case.
                          ///
                          /// This `func` takes care of the **Retrieve** part of the CRUD pattern.
                          ///
                          /// - returns: the password if the user + host is registered, and a password is set; otherwise `nil`
                          ///
                          /// - throws: Any of the `KeychainError`s for a misconfigured or forbidden access.
                          mutating func password() throws -> String? {
                              let returnPointer = UnsafeMutablePointer.alloc(1)
                              returnPointer.initialize(nil)
                              
                              var terms = searchPattern()
                              terms[kSecReturnData] = true
                              osStatus = SecItemCopyMatching(terms, returnPointer)
                              
                              switch osStatus {
                              case noErr:
                                  
                                  if let password = (returnPointer.memory as? NSData),
                                      retval = String(data: password, encoding: NSUTF8StringEncoding)
                                  { return retval }
                                  else { return nil }
                                  
                              case errSecItemNotFound:
                                  return nil
                                  
                              default:
                                  throw KeychainError.fromOSStatus(osStatus)!
                              }
                          }
                          
                          /// Set a (new) password for the (new) user + host.
                          ///
                          /// * If the combination is registered, but the password is different, the record is updated.
                          /// * If they are not registered, the record is created, including the desired password.
                          ///
                          /// This `func` takes care of both the **Create** and **Update** parts of the CRUD pattern.
                          ///
                          /// - throws: Any of the `KeychainError` errors thrown by the underlying implementation.
                          ///
                          /// - parameters:
                          ///     - newPassword: The password to set for the user + host. The `func` will not validate it.
                          mutating func setPassword(newPassword: String) throws {
                              if let old = try? password(),
                                  oldPassword = old
                              {
                                  if newPassword == oldPassword {
                                      //  The password is already set. Nothing to do.
                                      return
                                  }
                                  else {
                                      //  Item exists but must be updated
                                      try updatePasswordInKeychain(newPassword)
                                  }
                              }
                              else {
                                  // nil oldPassword, meaning the item must be created.
                                  try createKeychainItemWithPassword(newPassword)
                              }
                          }
                          
                          /// Remove the user + host combination from the keychain.
                          ///
                          /// This `func` takes care of the **Delete** part of the CRUD pattern.
                          ///
                          /// - throws: Any of the `KeychainError` errors thrown by the underlying implementation.
                          mutating func delete() throws {
                              osStatus = SecItemDelete(searchPattern())
                              if let error = KeychainError.fromOSStatus(osStatus) {
                                  throw error
                              }
                          }
                          
                          // MARK: Convenience keychain access
                          
                          /// A minimal dictionary of search criteria for the user + host
                          private func searchPattern() -> [NSString: AnyObject] {
                              let retval: [NSString: AnyObject] = [
                                  // Entry class
                                  kSecClass         : kSecClassInternetPassword,
                                  kSecAttrProtocol  : kSecAttrProtocolHTTPS,
                                  kSecAttrAuthenticationType
                                      : kSecAttrAuthenticationTypeHTTPBasic,
                                  kSecAttrAccount   : user,
                                  kSecAttrServer    : host
                              ]
                              return retval
                          }
                          
                          /// Create a keychain item for the user + host, including password.
                          ///
                          /// It is assumed that no item matching the user + host is in the keychain.
                          ///
                          /// - parameters:
                          ///     - password: The password to store in the item.
                          ///
                          /// - throws: Any of the `KeychainError` errors, most likely `.Duplicate`.
                          private mutating func createKeychainItemWithPassword(password: String) throws {
                              let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding)!
                              var values = searchPattern()
                              values[kSecValueData] = passwordData
                              //  Prevent synchronization with other devices:
                              values[kSecAttrSynchronizable] = false
                              //  The device has to have been unlocked since last restart, and will not be transferred to another device (as from backup)
                              values[kSecAttrAccessible] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
                      
                              osStatus = SecItemAdd(values, nil)
                              if let error = KeychainError.fromOSStatus(osStatus) {
                                  throw error
                              }
                          }
                          
                          /// Replace the password for an existing keychain item for user + host.
                          ///
                          /// It is assumed that an item matching the user + host is in the keychain.
                          ///
                          /// - parameters:
                          ///     - password: The password to store in the item.
                          ///
                          /// - throws: Any of the `KeychainError` errors, most likely `.OperationOnMissing`.
                          private mutating func updatePasswordInKeychain(password: String) throws {
                              let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding)!
                              let updateData: [NSString: AnyObject] = [ kSecValueData: passwordData,
                                  //  Prevent synchronization with other devices:
                                  kSecAttrSynchronizable: false,
                                  //  The device has to have been unlocked since last restart, and will not be transferred to another device (as from backup)
                                  kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
                              ]
                              osStatus = SecItemUpdate(searchPattern(), updateData)
                              if let error = KeychainError.fromOSStatus(osStatus) {
                                  throw error
                              }
                          }
                      }
                      
                      • 53. Re: Keychain error -34018 (errSecMissingEntitlement)
                        aarmstrong Level 1 Level 1 (0 points)

                        Well, we are into the new year, engineers and managers at Apple are refreshed from a holiday break, so let's hope we hear something soon.

                        • 54. Re: Keychain error -34018 (errSecMissingEntitlement)
                          DrAma78 Level 1 Level 1 (0 points)

                          I don't know if this might be helpfull, but I have a mixed objc (started with objc) and swift app. I use SSKeychain (written in ObjC) to store and read info from the keychain.

                          The part in objc works fine: I can retrieve stored info.

                          When I try to get them using swift I obtain that error, the other weird issue is that on simulator and with ad-hoc builds everything seems to work.

                          I get this error only if I run the app on device (9.2) while debugging.

                          Other curious stuff is that after a restart I can retrieve stored info at the same line of code where I get this error.

                          Pretty annoing.

                          • 55. Re: Keychain error -34018 (errSecMissingEntitlement)
                            claudiop Level 1 Level 1 (0 points)

                            Has anyone seen keychain error -34018 with iOS 9.2.1?

                            • 56. Re: Keychain error -34018 (errSecMissingEntitlement)
                              GoRoS Level 1 Level 1 (0 points)

                              Yes, unfortunately we are still experiencing this problem in iOS 9.2.1. Very frustrating and disappointing to be honest.

                              • 57. Re: Keychain error -34018 (errSecMissingEntitlement)
                                Duncan C Level 1 Level 1 (0 points)

                                Quinn, You said the only fix you are aware of was to "restart the process." What process? securityd? It woudl be useful to know what to look for in the Activity Monitor Instrument.

                                 

                                And as a user application, we can't restart a system daemon like securityd, can we?

                                 

                                 

                                 

                                Duncan Champney

                                WareTo

                                • 58. Re: Keychain error -34018 (errSecMissingEntitlement)
                                  eskimo Apple Staff Apple Staff (11,355 points)

                                  You said the only fix you are aware of was to "restart the process." What process?

                                  The app itself.

                                  Share and Enjoy

                                  Quinn “The Eskimo!”
                                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                  let myEmail = "eskimo" + "1" + "@apple.com"

                                  • 59. Re: Keychain error -34018 (errSecMissingEntitlement)
                                    mohpor2 Level 1 Level 1 (0 points)

                                    I'm going completely mad at the moment

                                    How can it be this annoying?

                                     

                                    In my case it's even weirder! I have a lot of logs concerning this issue. I have logs whith memory pressure being really high (marked with a nice "Received memory warning." message from os) and the access still works, and cases with a vast free memory and still get this error!!! I guess this being related to memory pressure might be a complete hoax.

                                    On the other hand, I always face this problem on consecutive runs, i.e. My first run will always work (regardless of memory pressure) second or third work 50% and after that it just fails. And to add some more interesting observations, I don't need to actually free any memory or restart the device, just waiting on it for a couple of minutes will do!

                                     

                                    Somebody kill me now. I don't want to raise a child in a world were I can't rely on apple to fix an error so wide spread!

                                     

                                    On my tomb stone you'll read: "There was a keychain, but there were no access"

                                    1 2 3 4 5 6 Previous Next