1 Testing the NISCC SSL Certs 2 Last Update 12 Nov 2003 by dmitch 3 4Introduction 5------------ 6Per 3479950, the British NISCC has discovered a vulnerability in almost 7all existing SSL implementation which can result in a Denial of Service 8attack when certain badly formatted DER elements are sent by the client 9the the server. Specifically the badly formatted element is the client 10cert. NISCC has provided a huge array of test certs to verify this 11problem. They've distrubuted this set of certs on a CD. 12 13This directory contains some of that CD, plus some X-specific tools 14to test and verify. The bulk of the CD is in the form of 6 large tarred 15and zipped bundles of bad certs. Those .tar.gz files are not in the 16CVS repositoty because they are so big. When those files are expanded, 17they result in hundreds of thousands of (bad) certs. Those certs are 18not in the CVS repository either. 19 20Details of the failures we're testing for 21----------------------------------------- 22As of this writing, there are three specific bugs in the SecurityNssAsn1 23library which can all cause crashes when an app attempts to decode 24certain badly formatted DER. All bugs are in 25SecurityNssAsn1/nssDER/Source/secasn1d.c. 26 27First, when doing an SEC_ASN1_SAVE operation (e.g., saving the 28still-encoded subject and issuer names in NSS_TBSCertificate.derIssuer and 29NSS_TBSCertificate.derSubject), the code allocates a SECItem for the 30whole blob solely based upon the length of the blob indicated in its 31enclosing DER sequence or set. However when traversing the actual bits 32being saved, each element is copied to the pre-allocated buffer according 33to the length field of that element. Corruption and crash can result if 34those inner length fields are bad and end up adding up to a size larger than 35the preallocated SECItem buffer. The solution is to track the allocated size 36of the buffer in sec_asn1d_state_struct.dest_alloc_len, which gets inherited 37from parent to child state as does the dest field itself. Whenever an item 38is appended to the dest SECItem, possible overflow is checked and the op 39aborts if an overflow would result. 40 41Second, the sec_asn1d_reuse_encoding() routine is called after a 42(successful) SEC_ASN1_SAVE op to "back up" to the forked location and 43resume decoding it "for real", using the saved-off buffer - NOT the 44caller's input. There was a bug here in that a "needBytes" error in the 45sec_asn1d_reuse_encoding()'s call to SEC_ASN1DecoderUpdate() was ignored 46and thrown out by the calling SEC_ASN1DecoderUpdate(), and processing 47proceeds, with possibly hazardous and unpredicatable results. However 48a "needBytes" error in the SEC_ASN1DecoderUpdate actually 49called by sec_asn1d_reuse_encoding() must be fatal since all the data 50is already present - we're not streaming when that update is called 51because all of the data is already present in the saved-off buffer. The 52solution is for sec_asn1d_reuse_encoding to detect the needBytes status and 53convert it into decodeError, thus aborting the caller immediately. (Note 54that this generally did not result in a crash, but in undetected decoding 55errors.) 56 57The third bug involved the behavior of the decoding engine if incoming 58encoded data claimed to have a very large length. Two problems can occur 59in sec_asn1d_prepare_for_contents() in such a case. First of course is the 60result of trying to malloc the large size. If state->contents_length is 612**32-1, for example, that malloc will almost certainly either fail or 62take much longer than is appropriate. Then there is some arithmetic 63involving appending subitems to the alloc_len which can result in 64integer overflow: 65 66 for (subitem = state->subitems_head; 67 subitem != NULL; subitem = subitem->next) 68 alloc_len += subitem->len; 69 } 70 71This bug is avoided by placing a somewhat arbitrary, but perfectly reasonable, 72restriction in sec_asn1d_parse_more_length() - the routine which parses 73such a huge length - that a 32-bit length value with the m.s. bit set is 74invalid. 75 76 77Testing overview 78---------------- 79There are two flavors of testing provided here. One uses a custom SSL 80client, nisccSimpleClient, which performs actual SSL transactions with 81an SSL server. The SSL server uses a good cert and requires client 82authentication. The SSL client uses a bad cert. Both are based on 83SecureTransport. A failure is indicated by the server crashing and 84failing to respond to any more client requests. 85 86The other method of testing focusses exlusively on the failure mode, 87which is the decoding and parsing of the bad certs. (The gross failure 88mode in an SSL server noted in the previous paragraph is always caused 89by the server crashing during the decoding of the client cert.) This testing 90is performed by a program called certDecode which simply attempts to decode 91every cert in cwd. This is way, way faster than setting up actual SSL 92clients and doing SSL transactions. As a result, the entire suite of 93"bad" client certs provided by NISCC (about 200,000 certs) has in fact 94been verified by this program. Resources to perform 200,000 SSL client 95trasnactions have not been marshalled as of this writing. In the opinion 96of this author, simply verifying that a process can attempt to decode the 97bad certs, without crashing, is sufficient for verifying that the 98problem has been solved. 99 100Building the test programs 101-------------------------- 102The nisccSimpleClient program requires the presence of both the 103clxutils/clAppUtils directory and the library it builds. The other 104programs - certDecode and skipThisNisccCert - just link against 105libCdsaUtils.a. None of these build in a way which is compatible with 106Jasper Makefiles or PB project files. All you need to do is to set the 107LOCAL_BUILD_DIR environment variable to point to the place where the 108executables go. YOu can build each program individually by cd'ing to 109the program directory and typing 'make', or just do a 'make' from 110here (which is assumed to be clxutils/NISCC/TLS_SSL), which builds 111all three. 112 113Testing using certDecode 114------------------------ 115The certDecode program is a standalone executable which uses the 116SecurityNssAsn1 library to simply attempt to decode either every cert 117in cwd, or the single cert specified in the cmd line. Build it by 118doing 'make' in its directory. You must have the $LOCAL_BUILD_DIR 119environment set. 120 121You need to obtain and untar one of the NISCC cert bundles. The two 122of main concern are simple_client.tar.gz and resigned_client.tar.gz. 123Each one of these explodes into about 100,000 certs taking up about 124200 MB of disk space. To run the test, cd to the directory containing 125100,000 certs and just run "certDecode" with no args. THe result will look 126something like this: 127 128 % tower.local:simple_client> certDecode 129 ....00000001...00000002...00000003...00000004...00000005... 130 00000006...00000007...00000008...00000009...00000010...00000011... 131 00000012...00000013...00000014...00000015...00000016...00000017... 132 ...etc.... 133 134It takes about 30 minutes to run thru all 100000 certs. Two things 135will happen: either the program will crash, or you'll see this at the 136end: 137 138 00106148...00106149...00106150...00106151...00106152...00106153... 139 00106154...00106155...00106156...00106157...00106158...00106159... 140 00106160 141 certDecode did not crash. 142 % 143 144Test using nisccSimpleClient 145---------------------------- 146 147WARNING this hasn't been tested in a long time (as of 7/18/06). The 148nisccSimpleClient builds as of this date but the status of rest of this 149is unknown. Stick to the certDecode test, above, which was verified as 150of 7/18/06. 151 152This is much more complicated and takes way longer than the certDecode 153test - so long that I still haven't run it with all 200,000 NISCC certs. 154But to get started here's what you need to do. 155 156First you need to build the sslServer program, in clxutils/sslServer. See 157the README in clxutils for build instructions. 158 159You also need the cspxutils/dbTool program. Your PATH variable needs 160to include the directory where its executable lives (generally, this is 161the same as your LOCAL_BUILD_DIR env var.) 162 163Then you need to build a custom Security.framework because certain errors 164introduced by this test will cause the stock SecureTransport library to 165(properly) abort client-side transactions before you get started due to 166badly formatted certs. The tag for this Security.framework NISCC_ASN1; 167that's a branch off of the PantherGM Security tree. Build the tree and 168either install it or make sure your DYLD_FRAMEWORK_PATH env var points 169to it for all subsequent testing. 170 171Now set up the SSL server keychain using the (good) NISCC-supplied server 172cert and key. In the NISCC/TLS_SSL/testcases directory do the following: 173 174 % rm -f ~/Library/Keychains/nisccServer 175 % certtool i server_crt.pem k=nisccServer r=server_key.pem c 176 177Run the sslServer app from the NISCC/TLS_SSL/testcases directory: 178 179 % sslServer l k=nisccServer P=1200 a rootca.crt u=t 180 181The "a rootca.crt" tells SecureTransport that the cert which signed the 182server's cert is a trusted root cert. The "u=t" tells the server to 183request client authentication. If all is well, this program just keeps 184on running, serving SSL requests, spewing forth to stdout (do not have 185an unlimited scrollback buffer in your Terminal window or your root disk 186will fill up.) 187 188Assuming that you'cve cd'd to the directory containing the nisccSslTest 189script (clxutils/NISCC/TLS_SSL/) and that the directory containing the 190untarred simple_client certs is in ./testcases/simple_client, just run 191the nisccSslTest script with one argument, the port number you supplied 192to the sslServer program above: 193 194 % nisccSslTest 1200 195 196This assumes that the following executables are accessible via your 197PATH variable: dbTool, nisccSimpleClient, and skipThisNisccCert. 198 199When this is running OK you'll see an endless spew on stdout like this: 200 201 cert 00001012... 202 ...DB /Volumes/Data_and_Apps/home/dmitch/Library/Keychains/nisccClient wiped clean 203 Starting nisccSimpleClient; args: localhost 1200 nisccClient 204 ===== nisccSimpleClient test PASSED ===== 205 cert 00001013... 206 ...DB /Volumes/Data_and_Apps/home/dmitch/Library/Keychains/nisccClient wiped clean 207 Starting nisccSimpleClient; args: localhost 1200 nisccClient 208 ===== nisccSimpleClient test PASSED ===== 209 cert 00001014... 210 ...DB /Volumes/Data_and_Apps/home/dmitch/Library/Keychains/nisccClient wiped clean 211 Starting nisccSimpleClient; args: localhost 13 1200 01 nisccClient 212 213...again, do not have an unlimited scrollback buffer in your Terminal 214window or your root disk will fill up. 215