{"id":2039,"date":"2011-07-29T16:57:24","date_gmt":"2011-07-29T20:57:24","guid":{"rendered":"http:\/\/www.red-sweater.com\/blog\/?p=2039"},"modified":"2011-07-29T17:04:08","modified_gmt":"2011-07-29T21:04:08","slug":"safari-keychain-woes","status":"publish","type":"post","link":"https:\/\/redsweater.com\/blog\/2039\/safari-keychain-woes","title":{"rendered":"Safari Keychain Woes"},"content":{"rendered":"<p>I&#8217;ve been running OS X Lion for a long time and generally enjoying it. But at some point along the line, Safari 5.1 stopped correctly inserting my keychain passwords into forms for me.<\/p>\n<p>For the longest time, I assumed it was simple mistakes: I had neglected to ever approve &#8220;remember this password,&#8221; or I had somehow invalidated the password in my keychain. But recently I have come to realize that Safari is no longer auto-filling passwords for me on any site. Ever. This sucks. Usually when something like this happens, the first thing I do is &#8220;Repair Keychain&#8221; from the Keychain Access application. But in this case, the keychain is reportedly not damaged. No help.<\/p>\n<p>To research this problem, I started the way I usually do: Googling it. While there are <a href=\"http:\/\/www.google.com\/search?client=safari&amp;rls=en&amp;q=safari+keychain+lion&amp;ie=UTF-8&amp;oe=UTF-8\">many promising search results<\/a>, most of them lead to &#8220;solutions&#8221; that are not applicable to my scenario. Most commonly it seems the user has somehow ended up with the appropriate &#8220;User names and passwords&#8221; checkbox being turned off in Safari&#8217;s AutoFill preferences.<\/p>\n<p>So how does a programmer like myself approach a problem like this? In recent years, Apple&#8217;s Instruments application has become an incredible asset for tracking down weird behavior not only in my own apps, but in other apps and in the system itself. I opened it up and started a new &#8220;Time Profiler&#8221; instrumentation session, targeting Safari. I know that Safari <em>used to<\/em> autofill my password whenever I typed in an account name that it recognized, so I start Instruments &#8220;sampling&#8221; Safari while I type my PayPal account name into the PayPal login page, and stop it after I&#8217;m done.<\/p>\n<p>I want to figure out where Safari is failing to get my password, so I take a wild leap and assume the corresponding function call in Safari contains the word &#8220;password.&#8221; Typing this into the Instruments search box yields promising results:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" title=\"Instruments.png\" src=\"http:\/\/www.red-sweater.com\/blog\/wp-content\/downloads\/2011\/07\/Instruments.png\" border=\"0\" alt=\"Instruments\" width=\"448\" height=\"103\" \/><\/p>\n<p>Now I know that Safari is at least\u00a0<em>making an effort<\/em> to fetch the corresponding password for me. I see that it&#8217;s calling -[NSURLCredential password], which in turn calls a lower-level Keychain Services function, SecItemCopyMatching(). But why isn&#8217;t it filling in my password?<\/p>\n<p>At this point I switch to gdb, where i can attach to the running instance of Safari and dig a little deeper into the issue.<\/p>\n<pre>% gdb\n(gdb) attach Safari\n(gdb) b -[NSURLCredential password]\nBreakpoint 1 at 0x7fff8ddff4af\n(gdb) c\nContinuing.\n<\/pre>\n<p>I know from Instruments that Safari will call this method when it tries to autofill my password, so I go back to Safari and enter my PayPal ID again. Sure enough, Safari &#8220;freezes&#8221; indicating that gdb has interrupted it where my breakpoint was set. Now, I realize this isn&#8217;t for the faint of heart, but you can use gdb to effectively debug an application, even if you don&#8217;t have the source code. You just have to know a bit about how Apple&#8217;s compiler translates source code into corresponding assembly language instructions, and where the <a href=\"http:\/\/www.clarkcox.com\/blog\/2009\/02\/04\/inspecting-obj-c-parameters-in-gdb\/\">arguments are placed<\/a> when calling methods.<\/p>\n<pre>Breakpoint 1, 0x00007fff8ddff4af in\n-[NSURLCredential password] ()\n(gdb) d\nDelete all breakpoints? (y or n) y\n(gdb) po $rdi\n&lt;NSURLCredential: 0x7ffd34d62920&gt;: paypal@jalkut.com\n(gdb) po [$rdi password]\n2: x\/i $pc  0x7fff9192760e &lt;gdb_class_getClass+4&gt;:\n\tmov    0x20(%rdi),%rax\nCan't print the description of a NIL object.\n(gdb)\n(gdb) p (int) [$rdi hasPassword]\n$11 = 1\n<\/pre>\n<p>What I&#8217;ve done here is first delete the breakpoint, so I don&#8217;t get interrupted while poking around from gdb itself. Then, I display the NSURLCredential object&#8217;s description, confirming it corresponds to the account I&#8217;m trying to log into. Finally, I call the password method on this NSURLCredential object myself, so I can see quickly and easily what the response will be. Gdb&#8217;s objection to trying to print a NIL object confirms that <em>the password is not being returned.<\/em> I am further able to confirm with NSURLCredential&#8217;s &#8220;hasPassword&#8221; method that the keychain <em>does have a password for this account<\/em>, but it isn&#8217;t being returned.<\/p>\n<p>Here we have a situation where apparently Safari is trying to get my password, but the system is vexing it. Let&#8217;s confirm by setting a breakpoint a little deeper, at the Keychain Services level that we also noticed in Instruments.<\/p>\n<pre>(gdb) b SecItemCopyMatching\nBreakpoint 3 at 0x7fff85919582\n(gdb) c\nContinuing.\n\nBreakpoint 3, 0x00007fff85919582 in SecItemCopyMatching ()\n(gdb) po $rdi\n{\n    acct = \"paypal@jalkut.com\";\n    atyp = form;\n    cdat = \"2007-06-02 16:17:01 +0000\";\n    class = inet;\n    desc = \"Web form password\";\n    icmt = default;\n    labl = \"www.paypal.com (paypal@jalkut.com)\";\n    \"m_Limit\" = \"m_LimitOne\";\n    mdat = \"2011-07-29 15:30:15 +0000\";\n    port = 0;\n    ptcl = htps;\n    \"r_Data\" = 1;\n    srvr = \"www.paypal.com\";\n}\n<\/pre>\n<p>So far, so good. It looks like NSURLCredential is properly passing a set of criteria to the keychain, describing the kind of password item it&#8217;s looking for. I take a peek at the second argument to SecItemCopyMatching, which is a pointer to where the result will be stored, and then I ask gdb to continue executing until the function is complete.<\/p>\n<pre>(gdb) x\/x $rsi\n0x7fff62eb3590:\t0x0000000000000000\n(gdb) fin\nRun till exit from #0  0x00007fff85919582 in SecItemCopyMatching ()\n0x00007fff86417c29 in URLCredentialInternetPassword::copyPassword ()\n<\/pre>\n<p>When gdb returns control to me, I know the function has finished calling, so I examine the result area in memory.<\/p>\n<pre>(gdb) x\/x 0x7fff62eb3590\n0x7fff62eb3590:\t0x0000000000000000\n<\/pre>\n<p>Indeed, it&#8217;s NULL! What is going on, here? I decided to dust off my <a href=\"http:\/\/www.red-sweater.com\/blog\/170\/usable-keychain-scripting\">Usable Keychain Scripting<\/a> tool, which makes it easy to use AppleScript to search and inspect the keychain. Is the inability to access the password a system-wide thing, or just something that is vexing Safari?<\/p>\n<pre>tell application \"Usable Keychain Scripting\"\n\ttell current keychain\n\t\tpassword of keychain item \"www.paypal.com (paypal@jalkut.com)\"\n\tend tell\nend tell\n<\/pre>\n<p>The script works perfectly, first causing the system to ask permission to authorize &#8220;Usable Keychain Scripting&#8221; to access the keychain item, and then returning the expected password string. This got me thinking, is it possible I&#8217;ve somehow got Keychain Accessing refuse access only to Safari?<\/p>\n<p>When I look at the &#8220;Access Controls&#8221; for the affected keychain item, it lists Safari as one of the permitted apps. What the hell, I think. I&#8217;ll remove it from the list, and then re-add it. To try to &#8220;dislodge&#8221; something. Confoundingly, everytime I try to add it, it just silently fails to appear in the list. I am able to add any other app without an issue.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" title=\"AuthorizedApps.png\" src=\"http:\/\/www.red-sweater.com\/blog\/wp-content\/downloads\/2011\/07\/AuthorizedApps.png\" border=\"0\" alt=\"AuthorizedApps\" width=\"454\" height=\"330\" \/><\/p>\n<p>As a quick check, I change the setting to &#8220;Allow all applications to access this item,&#8221; and save the changes. When I return to Safari and type in the login name, it instantly fills in the password for me.<\/p>\n<p>My system has a functional keychain but Safari seems unable to be authorized to access it, either on a one-time basis or as a &#8220;always allow&#8221; permission. I finally got the clever idea to look at \/var\/log\/secure.log, which frankly, I should have done about 5 hours earlier. What&#8217;s this?<\/p>\n<pre>com.apple.SecurityServer[33]: suppressing keychain prompt\nfor invalidly signed client \/Applications\/Safari.app(2938)\n<\/pre>\n<p>Aha! So that would explain it. Funny, I don&#8217;t <em>remember<\/em> tweaking anything inside the Safari application bundle, but this is certainly a very real example of how a broken code signature on Mac OS X can cause extremely subtle, hard to track-down &#8220;bugs.&#8221; I re-signed the applicaton on my own:<\/p>\n<pre>codesign -f -s - \/Applications\/Safari.app\n<\/pre>\n<p>When I reopened the app, and went to PayPal&#8217;s site, voila! It prompted me for permission, I approved, and now everything is back to normal.<\/p>\n<p>I examined the Safari.app bundle contents to try to remember what I might have tweaked. Then my memory was jogged. I had opened and edited Safari&#8217;s Info.plist file to play around with some settings. Don&#8217;t ask, it&#8217;s an even longer story than this.<\/p>\n<p>I take full responsibility for getting myself into this mess. I&#8217;ll certainly be more careful in the future to consider the implications of breaking code signatures on apps. However, I do think that the failure behavior could have been more informative. That NSLog I found in the console about refusing to prompt the user because of a broken code signature, could have been presented as a dialog that would instantly inform the user something is fishy. If my copy of Safari <em>actually had been compromised<\/em> by a nefarious individual, I wouldn&#8217;t have thought twice about continuing to enter my passwords and trying my damnedest to get Keychain to share my passwords with the compromised application.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been running OS X Lion for a long time and generally enjoying it. But at some point along the line, Safari 5.1 stopped correctly inserting my keychain passwords into forms for me. For the longest time, I assumed it was simple mistakes: I had neglected to ever approve &#8220;remember this password,&#8221; or I had [&hellip;]<\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,65,66],"tags":[],"class_list":["post-2039","post","type-post","status-publish","format-standard","hentry","category-debugging","category-lion","category-security"],"_links":{"self":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/2039","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/comments?post=2039"}],"version-history":[{"count":7,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/2039\/revisions"}],"predecessor-version":[{"id":2046,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/posts\/2039\/revisions\/2046"}],"wp:attachment":[{"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/media?parent=2039"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/categories?post=2039"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/redsweater.com\/blog\/wp-json\/wp\/v2\/tags?post=2039"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}