Was the iOS SSL Flaw Deliberate?
schneier.com
schneier.com
Once again: the only reason this bug got so much attention and press is that it's easy for laypeople to get their heads around. All you have to understand is how "goto" works. The bug is vivid, and so (paradoxically) seems scarier.
Significantly worse bugs are found every week. Within a few days of the announcement of this TLS bug, a Flash bug was announced, after being detected in exploits in the wild, that enabled reliable drive-by hijackings of browsers --- multiple browsers. It was off the HN front page within an hour.
TLS bugs aren't even unusual. We get a new one every few years ago. Firefox managed a PKCS1v15 parsing bug that allowed anyone with a Python script and 30 milliseconds to generate a certificate for any domain. Other browsers have screwed up certificate chaining, so that any domain could sign any other domain. But nobody understands PKCS1v15 padding, nobody understands certificate chaining, and so nobody writes stories about these bugs. But their impact is identical to this one.
[1] https://news.ycombinator.com/item?id=7284290
(Edit: also, while it was 4 years ago and my memory's a bit fuzzy, I seem to recall the earlier, actually exploitable in the wild, PKCSv15 vulnerability was discussed a lot in the tech media and community. It just didn't get the mainstream media attention, most likely because it wasn't as badly mishandled and "obscure security issue fixed already" is much less of a story than "you're at risk now and there's nothing you can do, because someone fucked up".)
But as I said a few days ago (https://news.ycombinator.com/item?id=7284957) I think this far more likely to be an NSA-exploited bug than an arbitrary-code-execution bug in Flash, because it's something which can be exploited widely and quietly without worrying about accidentally causing new versions of the program to core dump and reveal the presence of the bug.
I hate to say it, but I think you're being insufficiently paranoid.
I'm coming around to your take on TLS, for what it's worth, although the only thing I can think of that's worse than TLS are the crypto transports generalist developers come up with.
In other words, you're not being objective. You already attribute good character to the people you know at Apple, and are therefore are looking for ways to defend them against an accusation that hasn't even been made. The fact that you unnecessarily called Schneiers current occupation as 'sad', imo, tends to support this rationalisation.
None of the issues with Flash or certificate verification bugs you bring up are relevant to the discussion Schneier is having about this being the perfect kind of backdoor, and that, if it were a backdoor, it would have been hugely successful over the last year or more.
I have no doubt at all that if NSA knew about this bug, they were exploiting it. That's what they do. It is not my argument that this bug is irrelevant to NSA.
It's unlikely that Apple would agree to sabotage their own products in a way that will eventually be detected and affect their own credibility. That's restricting the argument that people are making to a straw man, though. Have spies ever worked that way? What people are mostly speculating about is whether this was an intentionally introduced vulnerability, not the mechanism by which that would come about.
Let me give you the perspective of someone who is outside the security business but knows a good deal about PR and the media and how it operates. And selling books (one that I was doing was mentioned on the front page of the WSJ - all from PR that I organized on my own).
Schneier has certainly transformed himself and it's all about his image and selling books with his new found fame. I know it when I see it. Because as he just said in a way "it's what I would do if I wanted to..."
So in other words he has an axe to grind in getting mentioned in the media. Period. That doesn't mean what he is saying isn't correct in some fashion of course. But it does give credence to the statement "Another sad indicator of the level Schneier is playing at today". That level is publicity for Schneier. So to repeat myself, exactly what I'd be doing if I was him.
I agree with you based on the security people I know at Apple. However, I would be surprised if Apple's security people have enough time to carefully audit every line of security-relevant code which other people at Apple touch.
So you're absolutely sure that there is no developer (in the position) at Apple that would take a discrete paper bag of $$$ to make just a tiny error by hitting ctrl-v twice?
If I were the NSA, a strategy with much lower variance would be to hire a lot of smart folks to do the intense security reviews and testing that Apple (and many other companies, presumably) fail to do, and try to find bugs before they're patched. As tptacek has pointed out, there are plenty of these, and an organization with the resources of the NSA can probably find them frequently enough for most purposes without sticking its neck out.
The odds are that this engineer will never be revealed publicly, and it will not effect his/her reputation in any way.
>but small enough to not trigger questions about where it came from.
You don't think that the NSA has the ability to hide money?
And for what? The NSA can hide money, but you or I would quickly find ourselves talking with the IRS if our spending or bank accounts rose dramatically without a commensurate rise in reported income. We could probably hide a few thousand dollars a month under the table, but that doesn't sound like it would turn the head of even a particularly amoral Apple engineer already making six figures.
I'm not saying this scenario is impossible. But to be plausible, it requires both the perpetrator and the NSA to take on a degree of risk that doesn't seem to match the reward for either.
If this is standard procedure for the NSA and happens often, given the risk involved, why hasn't anyone been caught at it and publicly exposed?
If the NSA made an exception and executed some unusually elaborate cloak and dagger to seduce or blackmail an Apple employee for this change, why do we think it was for this vulnerability and not the dozens of others that are discovered annually?
Very very good point.
Until you made it, I might have thought "well of course NSA looks for bugs to exploit", but I didn't think through the implications.
Here we have Apple open sourcing their security code. They made the NSA's job 10x easier than w/o the source. So of course the NSA will lint and review and test and exploit Apple's source code. Intensively. It's low-hanging fruit, of the Apple variety. :)
Do you have any information, whether they're using any kind of of code -security- auditing tools?
Could it be that the programmer simply got a backdoor request, which s/he in protest implemented this way to ensure to be caught.
I don't agree. Most people don't even have a basic understanding of coding. I think that it has more to do with the fact that there are about 500 million vulnerable devices out there, and that we are talking about Apple. Remember Antennagate, it wasn't even that big of a deal and look at what the press made of it.
[edit]
Also I bet most readers of Schneier's bug know what goto is as well.
I think that's the reason why this bug should get a lot of attention and press. Most programmers can see this bug instantly, without even knowing the purpose of the code. How long does something like that in a (maybe the most) security-critical piece of code in a product go unseen and uncorrected without it being a result of maliciousness or incompetence?
How many dopey errors like this would have to be inserted into how many products to guarantee that the vast majority of communications could be monitored for (lets say) 5-10 years? 50 errors in 15 products? This single error compromised all iPhones, all iPads, and all Macs.
This sort of strategy would be the most efficient way for the NSA to spend money that I've ever heard of it doing. If money isn't exchanged (the companies aren't being paid to compromise themselves) we don't even have the evidence trail that outed RSA, who sabotaged their products in an equally deniable way.
I'm with the people asking who did the commit that introduced the bug. I'd like to know if they had any intelligence connections.
Can you think of a reason why that would be in any computer program, and if you saw it in while reading any code, wouldn't it either indicate some weird trick that you maybe don't understand (and should look up) or an obvious error?
It doesn't look like anything that any static analysis tool wouldn't instantly scream about, either. I can't think of a less subtle error to accomplish the same thing.
edit: http://blog.veracode.com/2014/02/do-not-pass-qa-do-not-goto-...
Veracode does static analysis of the binary, and says that it would be thwarted because it wouldn't know that some functions were meant to be called. Static code analysis would tell you that it was impossible for some of the code to be run.
edit 2:(the second comment on the vericode blog)
caf | February 24, 2014 11:05 pm
In the Evil Unit Tests part you can use code coverage tools to at least verify that your unit tests exercise all code paths. It won’t catch every bug, but it would have caught this one.
I'm talking about tools like http://oclint.org/ and http://clang-analyzer.llvm.org/
If they work anything like similar tools in other languages, they would have found this bug trivially.
Flash I know to be insane. I don't use Firefox. So, less reason to care.
But yes, Schneier has become the USA Today of security advice. A lot of people read USA Today, so it's important, but it's probably not where you go for deep or substantial analysis. (and, generally a week after everyone else has discussed an issue to death)
When you say "significantly worse bugs are found every week", are you considering them worse using Schneier's yardsticks above, or your own (which to me as a lay person appear to be their potential for damage)?
Is there a public test-suite that implementers can check against?
Plus, if there were tests, they just become another target.
* The TLS stacks all have different APIs, and you'll need some fine-grained configuration over client options to exercise the code.
* There are only a few important TLS stacks, and the effort required to build a test suite is probably greater than the effort required to build a TLS stack.
It would still be a cool project. If it exists, I'd love to hear about it.
http://www.theregister.co.uk/2014/02/20/flash_adobe_posts_em...
That was the day before the iOS update. You scared me for a moment that there was a flash update I had missed cause of all the hoopla around gotofail.
The likelihood is pretty simple, someone fucked up. On a potentially huge level, but a fuck up none the less. These things do unfortunately happen, and no doubt it'll prompt an internal review of their change management process, and their build chain, and what they can do to isolate issues like this in the future.
The fact that people can see the nature of the bug in the source code for themselves just makes the case that it was a deliberate backdoor even more deniable which, as Schneier is pointing out, is a very desirable property.
You're also assuming that a backdoor you can use indefinitely is desirable.
As an added side-benefit, any other proprietary or FOSS products that adopted this code are now vulnerable.
[0] https://en.wikipedia.org/wiki/Attribution_%28psychology%29#D...
As technically minded people we intrinsically understand that it could be the work of someone malicious, but we should also understand from personal experiences that fuck ups happen significantly more often than brown envelopes full of cash.
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
Some other check was added: if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
+ if ((err = SSLHashSHA1.foobar(&hashCtx, &signedParams)) != 0)
+ goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
Then that check was merged into another check, otherwise refactored, or decided it was not needed there anymore - but mistakenly only the added if ... line was removed: if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
- if ((err = SSLHashSHA1.foobar(&hashCtx, &signedParams)) != 0)
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
And that's how that ended-up the way that it did. if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
Then of course it was not the only change submitted, it must have been a pretty sizable diff of many files, and it slipped-by in all that. Security-55471/libsecurity_ssl/security_ssl/tls_digest.c
#ifdef KERNEL
static int HashSHA1Update(SSLBuffer *digestCtx, const SSLBuffer *data)
{
return ccHashUpdate(ccsha1_di(), digestCtx, data);
}
#else
static int HashSHA1Update(SSLBuffer *digestCtx, const SSLBuffer *data)
{
/* 64 bits cast: safe, SSL records are always smaller than 2^32 bytes */
assert(digestCtx->length >= sizeof(CC_SHA1_CTX));
CC_SHA1_CTX *ctx = (CC_SHA1_CTX *)digestCtx->data;
CC_SHA1_Update(ctx, data->data, (CC_LONG)data->length);
return 0;
}
#endif
const HashReference SSLHashSHA1 =
{
SSL_SHA1_DIGEST_LENGTH,
40,
SSL_SHA1_CONTEXT_SIZE,
HashSHA1Init,
HashSHA1Update,
HashSHA1Final,
HashSHA1Close,
HashSHA1Clone
};
Security-55179.13/libsecurity_ssl/security_ssl/sslDigests.c
static OSStatus HashSHA1Update(SSLBuffer *digestCtx, const SSLBuffer *data)
{
/* 64 bits cast: safe, SSL records are always smaller than 2^32 bytes */
assert(digestCtx->length >= sizeof(CC_SHA1_CTX));
CC_SHA1_CTX *ctx = (CC_SHA1_CTX *)digestCtx->data;
CC_SHA1_Update(ctx, data->data, (CC_LONG)data->length);
return noErr;
}
const HashReference SSLHashSHA1 =
{
sizeof(CC_SHA1_CTX),
CC_SHA1_DIGEST_LENGTH,
40,
HashSHA1Init,
HashSHA1Update,
HashSHA1Final,
HashSHA1Close,
HashSHA1Clone
};
Do you see how there was some simple refactoring going on there in the structure and how the entire in-kernel functionality was added? I could totally see debugging function being created and sprinkled in all the places after all the update()s were called while verifying kernel stuff was working then removed and in this one place one line not enough deleted.edit: Ha, I had my own copy paste error after getting bad gateway error, I fixed the duplicated code, sorry.
A single employee receiving a second paycheck from a three-letter organization could have been responsible. A vulnerability could have been used to plant it. And so on. Remember when everyone was railing about Google giving NSA a backdoor (cue a thousand "don't be evil" cries) when in reality the NSA and friends were simply exploiting a weakness of Google's network. The net effect was the same.
It could be intentional and still entirely unintentional as far as Apple the company is concerned.
And to the open source thing -- it sat there for 18 months. Indeed, it was caught [EDIT: Actually I don't know how it was caught. I faintly recall someone posting an issue someone submitted to Apple detailing some weird behavior with invalid private keys, but can't find it now]
Agreed, as far as Apple know it was a bug, but one of their staff could have been turned. But they'll be able to audit the change logs, and I imagine a company famously known for their OTT internal security would be preparing the car batteries and nipple clamps if they thought they'd found a bad actor.
In other words, it's only possible that it's an NSA job if it's also possible that it isn't. Something tells me therefore that we're unlikely ever to know for sure.
(I certainly shouldn't pretend to know much about C, but the above matches my understanding of the situation)
Of course, this presumes that the NSA needs to introduce bugs like this. I imagine they do just fine for now merely taking advantage of naturally occurring bugs.
I fear that it may end up as, "we already found the bug, we don't need tests now". But that's probably pessimistic of me.
Given that the code is publicly available it seems likely that bad actors would be using such tools (both proprietary and open) to find exploits for each release.
I remember Eric Raymond blogging about using Coverity to analyze gpsd but beyond that I don't recall any wider discussion about the issue.
The clang static analyzer: http://clang-analyzer.llvm.org
Valgrind: http://www.valgrind.org
Address Sanitizer: http://clang.llvm.org/docs/AddressSanitizer.html
The various -fsanitize options in clang (undefined behaviours, integer overflows etc): http://clang.llvm.org/docs/UsersManual.html#id28
http://en.wikipedia.org/wiki/List_of_tools_for_static_code_a...
Also there is oclint not listed there, which is pretty amazing, but it has a strange notation for ignoring wqrnings. splint is pretty good too though and still supports the legacy lint stuff like /* NOTREACHED /
BSD lint seems to work still (though it looks like the lintlib is no longer built on FreeBSD and stdlib is not lint clean!) but even it would have caught this gotofail:
01: #include <stdlib.h>
02:
03: int
04: main(int argc, char *argv[])
05: {
06: if (argc == 0)
07: goto fail;
08: goto fail;
09:
10: exit(0);
11:
12:
13: fail:
14: exit(1);
15: }
$ lint a.c
a.c:
stdlib.h(286): warning: ANSI C does not support 'long long' [265]
stdlib.h(287): warning: ANSI C does not support 'long long' [265]
stdlib.h(287): warning: ANSI C does not support 'long long' [265]
a.c(10): warning: statement not reached [193]
a.c(15): warning: function main falls off bottom without returning value [217]
a.c(4): warning: argument argv unused in function main [231]
_types.h(61): warning: struct __timer never defined [233]
_types.h(62): warning: struct __mq never defined [233]
lint: cannot find llib-lc.ln
Lint pass2:
exit used( a.c(10) ), but not defined
$ cc a.c
$ ./a.out
$ echo $?
1
edit: grrr, sorry small copy/paste mistakes before.And anyone who given a choice between SSL and TLS relies on TLS is not putting security as a top priority.
And why would anyone who cares even the slightest about security use Flash? Are you serious?
I guess this is why security consulting could be easy money... clients want to use Flash and "stay secure". Yeah, sure, we can handle that for you.
Well, now you cannot even use a Mac without the potential for HTTPS authentication not working. Better make sure the OS is updated. Sounds a lot like Microsoft. Maybe you could start a business updating Mac OS's.
"Does anyone know what's going on inside Apple?"
If they did they couldn't say. All employees are sworn to secrecy.
I blackhole all traffic from Apple devices to *.apple.com
You would not believe (or maybe you would, if you are a "security consultant" or some such)... you would not believe the amount of "phoning home" that these devices do.
I agree you can't trust "security consultants" who do their marketing via blogs and forums.
But you surely cannot trust Apple either.
The flaw was one line of code.
I'm curious. What is the size on the update?
Imagine if you could make the change yourself, recompile and dd an image to your device.
The one thing that points to it not being a backdoor is I doubt Apple would open source the code. Surely they'd maintain a separate branch or something?
Has Apple even publicly discussed the basic details of this bug? As far as I've seen, every single bit of analysis has come from outside the company, based on simply viewing the source code. Apple acknowledged that there is a vulnerability, but they haven't even said what it is in any detail.
To the more important questions 'Did the NSA almost immediately discover this bug' and 'Did they exploit it', I answer with a resounding yes.
[1]: http://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines
Here's my alternative but equally reasonable platitude: "Never attribute to incompetence what could be attributed to malice with plausible deniability."
But on the other hand, why didn't the compiler generate an "Unreachable Code" warning during build?
We have explicitly set this warning to "Treat as Error" during our builds.
if (cond) { goto fail; }
instead of:
if (cond) goto fail;
I've seen quite a lot of discussion surrounding the coding style around this "goto fail" vulnerability, but IMO that's missing the forest for the tree. If this coding error was truly a mistake (which I tend to believe) it was probably the result of a bogus copy/paste. Shit happens, no matter the coding style.
In my opinion the real problem is: why wasn't this code properly tested and audited? For crypto code it borders on gross negligence.
In particular, I disagree with TFA that "The flaw is subtle, and hard to spot while scanning the code". When you're used to read properly indented C code the 2nd "goto fail" with its weird indentation jumps to the eye IMO. Also the fact that the same statement is repeated twice in exactly the same way. I'm used to reading a lot of kernel code using the same kind of error handling and it really stands out IMO.
If this is an intentional bug, I think it's likely a hacker or just a disgruntled employee. But I'd be willing to wager that it was a tiredness error, rushed to implementation by an overworked and likely underpaid engineer deep within Apple.
No, that would be a sign that they were incompetent, because secretly communicating groups do use unusual chats, such as graphical children's chat applets, in-game communications, shoutboxes and such. Why wouldn't they?
I don't know, game chat systems seem like a pretty good place to conspire. Imagine something like Call of Duty, you can pretty obviously talk about attacks and targets without setting off any red flags since it would be indistinguishable from real game chat.
Or they're pretending to be incompetent so they have an excuse to swallow up World of Warcraft and Yahoo Messenger chat logs. Because they don't care about terrorists, they care about logging /everything/. It's about power.
Its not.
It is creating one.
That is why its imperative that we do something about the NSA.
And completely legal (from their perspective), whereas attacking foreign citizens gets into grey areas.
The NSA could, for example, compromise Comcast routers, use this bug to MITM every single SSL connection to e-mail servers, and collect literally millions of people's credentials and messages.
The cost of doing the equivalent with "break my jaw" techniques is astronomical. You'd need massive manpower, huge facilities, and of course the public backlash would be almost incomprehensibly vast.
Programmers of all people should be able to understand that an automated, computerized solution can be applied to a large scale extremely cheaply, and that this is pretty much the only way to scale up to millions of users. In the NSA's case, it's targets instead of users, but the same principle applies.
The NSA wants all of the data. Technological measures is how to obtain it, and that's what they've been doing.
As with everything, gotos work just fine if you restrict yourself to a few specific uses. At that point, however, you've basically just invented function calls, switch statements, and maybe exceptions if your rules aren't strict enough, which can all be managed by a compiler which always generates the correct number of jmp's to do the job.
EDIT: you could more accurately replace each instance of "function call" in the above with "subroutine" as FORTRAN defines them, which is closer to what you get for free with gotos than a function call with an actual stack pointer.
No, this is false, both at the high-level-language and assembly-language level:
http://en.wikipedia.org/wiki/X86_calling_conventions
A function call transparently returns to the point at which the call originated and resumes execution. A GOTO departs from the original location, never to return. That is a crucial difference.
> EDIT: you could more accurately replace each instance of "function call" in the above with "subroutine" as FORTRAN defines them, which is closer to what you get for free with gotos than a function call with an actual stack pointer.
Still wrong -- you're confusing two very different things. A function call, in both the assembly and high-level sense, is completely different from a GOTO instruction.
(combined with a global pointer to a stack, a few instructions and a jmp should be enough to reimplement functions, including storing the return jmp address somewhere, obviously. As I think I made clear, I believe we invented compilers so that we don't have to know how this stuff is actually implemented. I do realise that I'm never going to know more about assembly than the set of HN readers who will pounce on this kind of comment - I was just trying to show that I have heard of jmp, and that I know it is spat out by compilers to implement high level language features, and that any nontrivial compiled program will contain many jmp instructions. A bug from using goto where a switch or if/else statement would have worked is inexcusable, and also nothing to do with assembly instructions.)
[1] actually, iOS 7? I take that back.
Yes, and there's a reason -- chip design should reflect how computers are programmed at a higher level, and function calls produce code that's easier to understand, create and maintain. The reason is that function calls obey a logical hierarchy that often reflects the meaning of the algorithm being executed.
To see the point, try creating a recursive-descent parser that uses GOTO and avoids function calls.
This understanding isn't limited to an HN gaggle of nattering bystanders:
http://www.u.arizona.edu/~rubinson/copyright_violations/Go_T...
> I was just trying to show that I have heard of jmp, and that I know it is spat out by compilers to implement high level language features, and that any nontrivial compiled program will contain many jmp instructions.
Yes, but what a compiler does, and what a high-level language does, are often completely different. As one example, many recursive algorithms are compiled into functionally equivalent loops, to make them more efficient and to keep from blowing up the stack.
My point is that a compiler's output doesn't have to be read by a human, so it can break every rule. Not so for a high-level code listing that might have to be understood and maintained over decades.
The author can't be serious. This particular bug has made the rounds and is understood even by non-programmers.