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