106 ProtocolVersion getHelloVersion() { |
75 ProtocolVersion getHelloVersion() { |
107 return helloVersion; |
76 return helloVersion; |
108 } |
77 } |
109 |
78 |
110 /* |
79 /* |
111 * Enable format checks if initial handshaking hasn't completed |
80 * Set instance for the computation of handshake hashes. |
112 */ |
81 * |
113 void enableFormatChecks() { |
|
114 formatVerified = false; |
|
115 } |
|
116 |
|
117 // return whether the data in this record is valid, decrypted data |
|
118 boolean isAppDataValid() { |
|
119 return appDataValid; |
|
120 } |
|
121 |
|
122 void setAppDataValid(boolean value) { |
|
123 appDataValid = value; |
|
124 } |
|
125 |
|
126 /* |
|
127 * Return the content type of the record. |
|
128 */ |
|
129 byte contentType() { |
|
130 return buf[0]; |
|
131 } |
|
132 |
|
133 /* |
|
134 * For handshaking, we need to be able to hash every byte above the |
82 * For handshaking, we need to be able to hash every byte above the |
135 * record marking layer. This is where we're guaranteed to see those |
83 * record marking layer. This is where we're guaranteed to see those |
136 * bytes, so this is where we can hash them ... especially in the |
84 * bytes, so this is where we can hash them ... especially in the |
137 * case of hashing the initial V2 message! |
85 * case of hashing the initial V2 message! |
138 */ |
86 */ |
139 void setHandshakeHash(HandshakeHash handshakeHash) { |
87 void setHandshakeHash(HandshakeHash handshakeHash) { |
|
88 if (handshakeHash != null) { |
|
89 byte[] reserved = null; |
|
90 if (this.handshakeHash != null) { |
|
91 reserved = this.handshakeHash.getAllHandshakeMessages(); |
|
92 } |
|
93 if ((reserved != null) && (reserved.length != 0)) { |
|
94 handshakeHash.update(reserved, 0, reserved.length); |
|
95 |
|
96 if (debug != null && Debug.isOn("data")) { |
|
97 Debug.printHex( |
|
98 "[reserved] handshake hash: len = " + reserved.length, |
|
99 reserved); |
|
100 } |
|
101 } |
|
102 } |
|
103 |
140 this.handshakeHash = handshakeHash; |
104 this.handshakeHash = handshakeHash; |
141 } |
105 } |
142 |
106 |
143 HandshakeHash getHandshakeHash() { |
107 boolean seqNumIsHuge() { |
144 return handshakeHash; |
108 return (readAuthenticator != null) && |
145 } |
109 readAuthenticator.seqNumIsHuge(); |
146 |
110 } |
147 void decrypt(Authenticator authenticator, |
111 |
148 CipherBox box) throws BadPaddingException { |
112 boolean isEmpty() { |
149 BadPaddingException reservedBPE = null; |
113 return false; |
150 int tagLen = |
114 } |
151 (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; |
115 |
152 int cipheredLength = count - headerSize; |
116 // apply to DTLS SSLEngine |
153 |
117 void expectingFinishFlight() { |
154 if (!box.isNullCipher()) { |
118 // blank |
155 try { |
119 } |
156 // apply explicit nonce for AEAD/CBC cipher suites if needed |
|
157 int nonceSize = box.applyExplicitNonce(authenticator, |
|
158 contentType(), buf, headerSize, cipheredLength); |
|
159 pos = headerSize + nonceSize; |
|
160 lastHashed = pos; // don't digest the explicit nonce |
|
161 |
|
162 // decrypt the content |
|
163 int offset = headerSize; |
|
164 if (box.isAEADMode()) { |
|
165 // DON'T encrypt the nonce_explicit for AEAD mode |
|
166 offset += nonceSize; |
|
167 } // The explicit IV for CBC mode can be decrypted. |
|
168 |
|
169 // Note that the CipherBox.decrypt() does not change |
|
170 // the capacity of the buffer. |
|
171 count = offset + |
|
172 box.decrypt(buf, offset, count - offset, tagLen); |
|
173 |
|
174 // Note that we don't remove the nonce from the buffer. |
|
175 } catch (BadPaddingException bpe) { |
|
176 // RFC 2246 states that decryption_failed should be used |
|
177 // for this purpose. However, that allows certain attacks, |
|
178 // so we just send bad record MAC. We also need to make |
|
179 // sure to always check the MAC to avoid a timing attack |
|
180 // for the same issue. See paper by Vaudenay et al and the |
|
181 // update in RFC 4346/5246. |
|
182 // |
|
183 // Failover to message authentication code checking. |
|
184 reservedBPE = bpe; |
|
185 } |
|
186 } |
|
187 |
|
188 // Requires message authentication code for null, stream and block |
|
189 // cipher suites. |
|
190 if (authenticator instanceof MAC && tagLen != 0) { |
|
191 MAC signer = (MAC)authenticator; |
|
192 int macOffset = count - tagLen; |
|
193 int contentLen = macOffset - pos; |
|
194 |
|
195 // Note that although it is not necessary, we run the same MAC |
|
196 // computation and comparison on the payload for both stream |
|
197 // cipher and CBC block cipher. |
|
198 if (contentLen < 0) { |
|
199 // negative data length, something is wrong |
|
200 if (reservedBPE == null) { |
|
201 reservedBPE = new BadPaddingException("bad record"); |
|
202 } |
|
203 |
|
204 // set offset of the dummy MAC |
|
205 macOffset = headerSize + cipheredLength - tagLen; |
|
206 contentLen = macOffset - headerSize; |
|
207 } |
|
208 |
|
209 count -= tagLen; // Set the count before any MAC checking |
|
210 // exception occurs, so that the following |
|
211 // process can read the actual decrypted |
|
212 // content (minus the MAC) in the fragment |
|
213 // if necessary. |
|
214 |
|
215 // Run MAC computation and comparison on the payload. |
|
216 if (checkMacTags(contentType(), |
|
217 buf, pos, contentLen, signer, false)) { |
|
218 if (reservedBPE == null) { |
|
219 reservedBPE = new BadPaddingException("bad record MAC"); |
|
220 } |
|
221 } |
|
222 |
|
223 // Run MAC computation and comparison on the remainder. |
|
224 // |
|
225 // It is only necessary for CBC block cipher. It is used to get a |
|
226 // constant time of MAC computation and comparison on each record. |
|
227 if (box.isCBCMode()) { |
|
228 int remainingLen = calculateRemainingLen( |
|
229 signer, cipheredLength, contentLen); |
|
230 |
|
231 // NOTE: remainingLen may be bigger (less than 1 block of the |
|
232 // hash algorithm of the MAC) than the cipheredLength. However, |
|
233 // We won't need to worry about it because we always use a |
|
234 // maximum buffer for every record. We need a change here if |
|
235 // we use small buffer size in the future. |
|
236 if (remainingLen > buf.length) { |
|
237 // unlikely to happen, just a placehold |
|
238 throw new RuntimeException( |
|
239 "Internal buffer capacity error"); |
|
240 } |
|
241 |
|
242 // Won't need to worry about the result on the remainder. And |
|
243 // then we won't need to worry about what's actual data to |
|
244 // check MAC tag on. We start the check from the header of the |
|
245 // buffer so that we don't need to construct a new byte buffer. |
|
246 checkMacTags(contentType(), buf, 0, remainingLen, signer, true); |
|
247 } |
|
248 } |
|
249 |
|
250 // Is it a failover? |
|
251 if (reservedBPE != null) { |
|
252 throw reservedBPE; |
|
253 } |
|
254 } |
|
255 |
|
256 /* |
|
257 * Run MAC computation and comparison |
|
258 * |
|
259 * Please DON'T change the content of the byte buffer parameter! |
|
260 */ |
|
261 static boolean checkMacTags(byte contentType, byte[] buffer, |
|
262 int offset, int contentLen, MAC signer, boolean isSimulated) { |
|
263 |
|
264 int tagLen = signer.MAClen(); |
|
265 byte[] hash = signer.compute( |
|
266 contentType, buffer, offset, contentLen, isSimulated); |
|
267 if (hash == null || tagLen != hash.length) { |
|
268 // Something is wrong with MAC implementation. |
|
269 throw new RuntimeException("Internal MAC error"); |
|
270 } |
|
271 |
|
272 int[] results = compareMacTags(buffer, offset + contentLen, hash); |
|
273 return (results[0] != 0); |
|
274 } |
|
275 |
|
276 /* |
|
277 * A constant-time comparison of the MAC tags. |
|
278 * |
|
279 * Please DON'T change the content of the byte buffer parameter! |
|
280 */ |
|
281 private static int[] compareMacTags( |
|
282 byte[] buffer, int offset, byte[] tag) { |
|
283 |
|
284 // An array of hits is used to prevent Hotspot optimization for |
|
285 // the purpose of a constant-time check. |
|
286 int[] results = {0, 0}; // {missed #, matched #} |
|
287 |
|
288 // The caller ensures there are enough bytes available in the buffer. |
|
289 // So we won't need to check the length of the buffer. |
|
290 for (int i = 0; i < tag.length; i++) { |
|
291 if (buffer[offset + i] != tag[i]) { |
|
292 results[0]++; // mismatched bytes |
|
293 } else { |
|
294 results[1]++; // matched bytes |
|
295 } |
|
296 } |
|
297 |
|
298 return results; |
|
299 } |
|
300 |
|
301 /* |
|
302 * Calculate the length of a dummy buffer to run MAC computation |
|
303 * and comparison on the remainder. |
|
304 * |
|
305 * The caller MUST ensure that the fullLen is not less than usedLen. |
|
306 */ |
|
307 static int calculateRemainingLen( |
|
308 MAC signer, int fullLen, int usedLen) { |
|
309 |
|
310 int blockLen = signer.hashBlockLen(); |
|
311 int minimalPaddingLen = signer.minimalPaddingLen(); |
|
312 |
|
313 // (blockLen - minimalPaddingLen) is the maximum message size of |
|
314 // the last block of hash function operation. See FIPS 180-4, or |
|
315 // MD5 specification. |
|
316 fullLen += 13 - (blockLen - minimalPaddingLen); |
|
317 usedLen += 13 - (blockLen - minimalPaddingLen); |
|
318 |
|
319 // Note: fullLen is always not less than usedLen, and blockLen |
|
320 // is always bigger than minimalPaddingLen, so we don't worry |
|
321 // about negative values. 0x01 is added to the result to ensure |
|
322 // that the return value is positive. The extra one byte does |
|
323 // not impact the overall MAC compression function evaluations. |
|
324 return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - |
|
325 Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen(); |
|
326 } |
|
327 |
|
328 /* |
|
329 * Well ... hello_request messages are _never_ hashed since we can't |
|
330 * know when they'd appear in the sequence. |
|
331 */ |
|
332 void ignore(int bytes) { |
|
333 if (bytes > 0) { |
|
334 pos += bytes; |
|
335 lastHashed = pos; |
|
336 } |
|
337 } |
|
338 |
|
339 /* |
|
340 * We hash the (plaintext) we've processed, but only on demand. |
|
341 * |
|
342 * There is one place where we want to access the hash in the middle |
|
343 * of a record: client cert message gets hashed, and part of the |
|
344 * same record is the client cert verify message which uses that hash. |
|
345 * So we track how much we've read and hashed. |
|
346 */ |
|
347 void doHashes() { |
|
348 int len = pos - lastHashed; |
|
349 |
|
350 if (len > 0) { |
|
351 hashInternal(buf, lastHashed, len); |
|
352 lastHashed = pos; |
|
353 } |
|
354 } |
|
355 |
|
356 /* |
|
357 * Need a helper function so we can hash the V2 hello correctly |
|
358 */ |
|
359 private void hashInternal(byte databuf [], int offset, int len) { |
|
360 if (debug != null && Debug.isOn("data")) { |
|
361 try { |
|
362 HexDumpEncoder hd = new HexDumpEncoder(); |
|
363 |
|
364 System.out.println("[read] MD5 and SHA1 hashes: len = " |
|
365 + len); |
|
366 hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len), |
|
367 System.out); |
|
368 } catch (IOException e) { } |
|
369 } |
|
370 handshakeHash.update(databuf, offset, len); |
|
371 } |
|
372 |
|
373 |
|
374 /* |
|
375 * Handshake messages may cross record boundaries. We "queue" |
|
376 * these in big buffers if we need to cope with this problem. |
|
377 * This is not anticipated to be a common case; if this turns |
|
378 * out to be wrong, this can readily be sped up. |
|
379 */ |
|
380 void queueHandshake(InputRecord r) throws IOException { |
|
381 int len; |
|
382 |
|
383 /* |
|
384 * Hash any data that's read but unhashed. |
|
385 */ |
|
386 doHashes(); |
|
387 |
|
388 /* |
|
389 * Move any unread data to the front of the buffer, |
|
390 * flagging it all as unhashed. |
|
391 */ |
|
392 if (pos > headerSize) { |
|
393 len = count - pos; |
|
394 if (len != 0) { |
|
395 System.arraycopy(buf, pos, buf, headerSize, len); |
|
396 } |
|
397 pos = headerSize; |
|
398 lastHashed = pos; |
|
399 count = headerSize + len; |
|
400 } |
|
401 |
|
402 /* |
|
403 * Grow "buf" if needed |
|
404 */ |
|
405 len = r.available() + count; |
|
406 if (buf.length < len) { |
|
407 byte newbuf []; |
|
408 |
|
409 newbuf = new byte [len]; |
|
410 System.arraycopy(buf, 0, newbuf, 0, count); |
|
411 buf = newbuf; |
|
412 } |
|
413 |
|
414 /* |
|
415 * Append the new buffer to this one. |
|
416 */ |
|
417 System.arraycopy(r.buf, r.pos, buf, count, len - count); |
|
418 count = len; |
|
419 |
|
420 /* |
|
421 * Adjust lastHashed; important for now with clients which |
|
422 * send SSL V2 client hellos. This will go away eventually, |
|
423 * by buffer code cleanup. |
|
424 */ |
|
425 len = r.lastHashed - r.pos; |
|
426 if (pos == headerSize) { |
|
427 lastHashed += len; |
|
428 } else { |
|
429 throw new SSLProtocolException("?? confused buffer hashing ??"); |
|
430 } |
|
431 // we've read the record, advance the pointers |
|
432 r.pos = r.count; |
|
433 } |
|
434 |
|
435 |
120 |
436 /** |
121 /** |
437 * Prevent any more data from being read into this record, |
122 * Prevent any more data from being read into this record, |
438 * and flag the record as holding no data. |
123 * and flag the record as holding no data. |
439 */ |
124 */ |
440 @Override |
125 @Override |
441 public void close() { |
126 synchronized public void close() throws IOException { |
442 appDataValid = false; |
127 if (!isClosed) { |
443 isClosed = true; |
128 isClosed = true; |
444 mark = 0; |
129 readCipher.dispose(); |
445 pos = 0; |
130 } |
446 count = 0; |
131 } |
447 } |
132 |
448 |
133 // apply to SSLSocket and SSLEngine |
|
134 void changeReadCiphers( |
|
135 Authenticator readAuthenticator, CipherBox readCipher) { |
|
136 |
|
137 /* |
|
138 * Dispose of any intermediate state in the underlying cipher. |
|
139 * For PKCS11 ciphers, this will release any attached sessions, |
|
140 * and thus make finalization faster. |
|
141 * |
|
142 * Since MAC's doFinal() is called for every SSL/TLS packet, it's |
|
143 * not necessary to do the same with MAC's. |
|
144 */ |
|
145 readCipher.dispose(); |
|
146 |
|
147 this.readAuthenticator = readAuthenticator; |
|
148 this.readCipher = readCipher; |
|
149 } |
|
150 |
|
151 // change fragment size |
|
152 void changeFragmentSize(int fragmentSize) { |
|
153 this.fragmentSize = fragmentSize; |
|
154 } |
449 |
155 |
450 /* |
156 /* |
451 * We may need to send this SSL v2 "No Cipher" message back, if we |
157 * Check if there is enough inbound data in the ByteBuffer to make |
452 * are faced with an SSLv2 "hello" that's not saying "I talk v3". |
158 * a inbound packet. |
453 * It's the only one documented in the V2 spec as a fatal error. |
159 * |
454 */ |
160 * @return -1 if there are not enough bytes to tell (small header), |
455 private static final byte[] v2NoCipher = { |
161 */ |
456 (byte)0x80, (byte)0x03, // unpadded 3 byte record |
162 // apply to SSLEngine only |
457 (byte)0x00, // ... error message |
163 int bytesInCompletePacket(ByteBuffer buf) throws SSLException { |
458 (byte)0x00, (byte)0x01 // ... NO_CIPHER error |
164 throw new UnsupportedOperationException(); |
459 }; |
165 } |
460 |
166 |
461 private int readFully(InputStream s, byte b[], int off, int len) |
167 // apply to SSLSocket only |
462 throws IOException { |
168 int bytesInCompletePacket(InputStream is) throws IOException { |
463 int n = 0; |
169 throw new UnsupportedOperationException(); |
464 while (n < len) { |
|
465 int readLen = s.read(b, off + n, len - n); |
|
466 if (readLen < 0) { |
|
467 return readLen; |
|
468 } |
|
469 |
|
470 if (debug != null && Debug.isOn("packet")) { |
|
471 try { |
|
472 HexDumpEncoder hd = new HexDumpEncoder(); |
|
473 ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen); |
|
474 |
|
475 System.out.println("[Raw read]: length = " + |
|
476 bb.remaining()); |
|
477 hd.encodeBuffer(bb, System.out); |
|
478 } catch (IOException e) { } |
|
479 } |
|
480 |
|
481 n += readLen; |
|
482 exlen += readLen; |
|
483 } |
|
484 |
|
485 return n; |
|
486 } |
|
487 |
|
488 /* |
|
489 * Read the SSL V3 record ... first time around, check to see if it |
|
490 * really IS a V3 record. Handle SSL V2 clients which can talk V3.0, |
|
491 * as well as real V3 record format; otherwise report an error. |
|
492 */ |
|
493 void read(InputStream s, OutputStream o) throws IOException { |
|
494 if (isClosed) { |
|
495 return; |
|
496 } |
|
497 |
|
498 /* |
|
499 * For SSL it really _is_ an error if the other end went away |
|
500 * so ungracefully as to not shut down cleanly. |
|
501 */ |
|
502 if(exlen < headerSize) { |
|
503 int really = readFully(s, buf, exlen, headerSize - exlen); |
|
504 if (really < 0) { |
|
505 throw new EOFException("SSL peer shut down incorrectly"); |
|
506 } |
|
507 |
|
508 pos = headerSize; |
|
509 count = headerSize; |
|
510 lastHashed = pos; |
|
511 } |
|
512 |
|
513 /* |
|
514 * The first record might use some other record marking convention, |
|
515 * typically SSL v2 header. (PCT could also be detected here.) |
|
516 * This case is currently common -- Navigator 3.0 usually works |
|
517 * this way, as do IE 3.0 and other products. |
|
518 */ |
|
519 if (!formatVerified) { |
|
520 formatVerified = true; |
|
521 /* |
|
522 * The first record must either be a handshake record or an |
|
523 * alert message. If it's not, it is either invalid or an |
|
524 * SSLv2 message. |
|
525 */ |
|
526 if (buf[0] != ct_handshake && buf[0] != ct_alert) { |
|
527 handleUnknownRecord(s, o); |
|
528 } else { |
|
529 readV3Record(s, o); |
|
530 } |
|
531 } else { // formatVerified == true |
|
532 readV3Record(s, o); |
|
533 } |
|
534 } |
170 } |
535 |
171 |
536 /** |
172 /** |
537 * Return true if the specified record protocol version is out of the |
173 * Return true if the specified record protocol version is out of the |
538 * range of the possible supported versions. |
174 * range of the possible supported versions. |
539 */ |
175 */ |
540 static void checkRecordVersion(ProtocolVersion version, |
176 void checkRecordVersion(ProtocolVersion version, |
541 boolean allowSSL20Hello) throws SSLException { |
177 boolean allowSSL20Hello) throws SSLException { |
542 // Check if the record version is too old (currently not possible) |
178 // blank |
543 // or if the major version does not match. |
179 } |
544 // |
180 |
545 // The actual version negotiation is in the handshaker classes |
181 // apply to DTLS SSLEngine only |
546 if ((version.v < ProtocolVersion.MIN.v) || |
182 Plaintext acquirePlaintext() |
547 ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) { |
183 throws IOException, BadPaddingException { |
548 |
184 throw new UnsupportedOperationException(); |
549 // if it's not SSLv2, we're out of here. |
185 } |
550 if (!allowSSL20Hello || |
186 |
551 (version.v != ProtocolVersion.SSL20Hello.v)) { |
187 // read, decrypt and decompress the network record. |
552 throw new SSLException("Unsupported record version " + version); |
188 // |
553 } |
189 // apply to SSLEngine only |
554 } |
190 Plaintext decode(ByteBuffer netData) |
555 } |
191 throws IOException, BadPaddingException { |
556 |
192 throw new UnsupportedOperationException(); |
557 /** |
193 } |
558 * Read a SSL/TLS record. Throw an IOException if the format is invalid. |
194 |
559 */ |
195 // apply to SSLSocket only |
560 private void readV3Record(InputStream s, OutputStream o) |
196 Plaintext decode(InputStream is, ByteBuffer destination) |
561 throws IOException { |
197 throws IOException, BadPaddingException { |
562 ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]); |
198 throw new UnsupportedOperationException(); |
563 |
199 } |
564 // check the record version |
200 |
565 checkRecordVersion(recordVersion, false); |
201 // apply to SSLSocket only |
566 |
202 void setDeliverStream(OutputStream outputStream) { |
567 /* |
203 throw new UnsupportedOperationException(); |
568 * Get and check length, then the data. |
204 } |
569 */ |
205 |
570 int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff); |
206 // calculate plaintext fragment size |
571 |
207 // |
572 /* |
208 // apply to SSLEngine only |
573 * Check for upper bound. |
209 int estimateFragmentSize(int packetSize) { |
574 */ |
210 throw new UnsupportedOperationException(); |
575 if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) { |
211 } |
576 throw new SSLProtocolException("Bad InputRecord size" |
212 |
577 + ", count = " + contentLen |
213 // |
578 + ", buf.length = " + buf.length); |
214 // shared helpers |
579 } |
215 // |
580 |
216 |
581 /* |
217 // Not apply to DTLS |
582 * Grow "buf" if needed. Since buf is maxRecordSize by default, |
218 static ByteBuffer convertToClientHello(ByteBuffer packet) { |
583 * this only occurs when we receive records which violate the |
219 |
584 * SSL specification. This is a workaround for a Microsoft SSL bug. |
220 int srcPos = packet.position(); |
585 */ |
221 int srcLim = packet.limit(); |
586 if (contentLen > buf.length - headerSize) { |
222 |
587 byte[] newbuf = new byte[contentLen + headerSize]; |
223 byte firstByte = packet.get(); |
588 System.arraycopy(buf, 0, newbuf, 0, headerSize); |
224 byte secondByte = packet.get(); |
589 buf = newbuf; |
225 int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2; |
590 } |
226 |
591 |
227 packet.position(srcPos + 3); // the V2ClientHello record header |
592 if (exlen < contentLen + headerSize) { |
228 |
593 int really = readFully( |
229 byte majorVersion = packet.get(); |
594 s, buf, exlen, contentLen + headerSize - exlen); |
230 byte minorVersion = packet.get(); |
595 if (really < 0) { |
231 |
596 throw new SSLException("SSL peer shut down incorrectly"); |
232 int cipherSpecLen = ((packet.get() & 0xFF) << 8) + |
597 } |
233 (packet.get() & 0xFF); |
598 } |
234 int sessionIdLen = ((packet.get() & 0xFF) << 8) + |
599 |
235 (packet.get() & 0xFF); |
600 // now we've got a complete record. |
236 int nonceLen = ((packet.get() & 0xFF) << 8) + |
601 count = contentLen + headerSize; |
237 (packet.get() & 0xFF); |
602 exlen = 0; |
238 |
603 |
239 // Required space for the target SSLv3 ClientHello message. |
604 if (debug != null && Debug.isOn("record")) { |
240 // 5: record header size |
605 if (count < 0 || count > (maxRecordSize - headerSize)) { |
241 // 4: handshake header size |
606 System.out.println(Thread.currentThread().getName() |
242 // 2: ClientHello.client_version |
607 + ", Bad InputRecord size" + ", count = " + count); |
243 // 32: ClientHello.random |
608 } |
244 // 1: length byte of ClientHello.session_id |
609 System.out.println(Thread.currentThread().getName() |
245 // 2: empty ClientHello.compression_methods |
610 + ", READ: " + recordVersion + " " |
246 int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 ); |
611 + contentName(contentType()) + ", length = " + available()); |
247 byte[] converted = new byte[requiredSize]; |
612 } |
|
613 /* |
|
614 * then caller decrypts, verifies, and uncompresses |
|
615 */ |
|
616 } |
|
617 |
|
618 /** |
|
619 * Deal with unknown records. Called if the first data we read on this |
|
620 * connection does not look like an SSL/TLS record. It could a SSLv2 |
|
621 * message, or just garbage. |
|
622 */ |
|
623 private void handleUnknownRecord(InputStream s, OutputStream o) |
|
624 throws IOException { |
|
625 /* |
|
626 * No? Oh well; does it look like a V2 "ClientHello"? |
|
627 * That'd be an unpadded handshake message; we don't |
|
628 * bother checking length just now. |
|
629 */ |
|
630 if (((buf[0] & 0x080) != 0) && buf[2] == 1) { |
|
631 /* |
|
632 * if the user has disabled SSLv2Hello (using |
|
633 * setEnabledProtocol) then throw an |
|
634 * exception |
|
635 */ |
|
636 if (helloVersion != ProtocolVersion.SSL20Hello) { |
|
637 throw new SSLHandshakeException("SSLv2Hello is disabled"); |
|
638 } |
|
639 |
|
640 ProtocolVersion recordVersion = |
|
641 ProtocolVersion.valueOf(buf[3], buf[4]); |
|
642 |
|
643 if (recordVersion == ProtocolVersion.SSL20Hello) { |
|
644 /* |
|
645 * Looks like a V2 client hello, but not one saying |
|
646 * "let's talk SSLv3". So we send an SSLv2 error |
|
647 * message, one that's treated as fatal by clients. |
|
648 * (Otherwise we'll hang.) |
|
649 */ |
|
650 try { |
|
651 writeBuffer(o, v2NoCipher, 0, v2NoCipher.length); |
|
652 } catch (Exception e) { |
|
653 /* NOTHING */ |
|
654 } |
|
655 throw new SSLException("Unsupported SSL v2.0 ClientHello"); |
|
656 } |
|
657 |
|
658 /* |
|
659 * If we can map this into a V3 ClientHello, read and |
|
660 * hash the rest of the V2 handshake, turn it into a |
|
661 * V3 ClientHello message, and pass it up. |
|
662 */ |
|
663 int len = ((buf[0] & 0x7f) << 8) + |
|
664 (buf[1] & 0xff) - 3; |
|
665 if (v2Buf == null) { |
|
666 v2Buf = new byte[len]; |
|
667 } |
|
668 if (exlen < len + headerSize) { |
|
669 int really = readFully( |
|
670 s, v2Buf, exlen - headerSize, len + headerSize - exlen); |
|
671 if (really < 0) { |
|
672 throw new EOFException("SSL peer shut down incorrectly"); |
|
673 } |
|
674 } |
|
675 |
|
676 // now we've got a complete record. |
|
677 exlen = 0; |
|
678 |
|
679 hashInternal(buf, 2, 3); |
|
680 hashInternal(v2Buf, 0, len); |
|
681 V2toV3ClientHello(v2Buf); |
|
682 v2Buf = null; |
|
683 lastHashed = count; |
|
684 |
|
685 if (debug != null && Debug.isOn("record")) { |
|
686 System.out.println( |
|
687 Thread.currentThread().getName() |
|
688 + ", READ: SSL v2, contentType = " |
|
689 + contentName(contentType()) |
|
690 + ", translated length = " + available()); |
|
691 } |
|
692 return; |
|
693 |
|
694 } else { |
|
695 /* |
|
696 * Does it look like a V2 "ServerHello"? |
|
697 */ |
|
698 if (((buf [0] & 0x080) != 0) && buf [2] == 4) { |
|
699 throw new SSLException( |
|
700 "SSL V2.0 servers are not supported."); |
|
701 } |
|
702 |
|
703 /* |
|
704 * If this is a V2 NoCipher message then this means |
|
705 * the other server doesn't support V3. Otherwise, we just |
|
706 * don't understand what it's saying. |
|
707 */ |
|
708 for (int i = 0; i < v2NoCipher.length; i++) { |
|
709 if (buf[i] != v2NoCipher[i]) { |
|
710 throw new SSLException( |
|
711 "Unrecognized SSL message, plaintext connection?"); |
|
712 } |
|
713 } |
|
714 |
|
715 throw new SSLException("SSL V2.0 servers are not supported."); |
|
716 } |
|
717 } |
|
718 |
|
719 /* |
|
720 * Actually do the write here. For SSLEngine's HS data, |
|
721 * we'll override this method and let it take the appropriate |
|
722 * action. |
|
723 */ |
|
724 void writeBuffer(OutputStream s, byte [] buf, int off, int len) |
|
725 throws IOException { |
|
726 s.write(buf, 0, len); |
|
727 s.flush(); |
|
728 } |
|
729 |
|
730 /* |
|
731 * Support "old" clients which are capable of SSL V3.0 protocol ... for |
|
732 * example, Navigator 3.0 clients. The V2 message is in the header and |
|
733 * the bytes passed as parameter. This routine translates the V2 message |
|
734 * into an equivalent V3 one. |
|
735 */ |
|
736 private void V2toV3ClientHello(byte v2Msg []) throws SSLException |
|
737 { |
|
738 int i; |
|
739 |
248 |
740 /* |
249 /* |
741 * Build the first part of the V3 record header from the V2 one |
250 * Build the first part of the V3 record header from the V2 one |
742 * that's now buffered up. (Lengths are fixed up later). |
251 * that's now buffered up. (Lengths are fixed up later). |
743 */ |
252 */ |
744 buf [0] = ct_handshake; |
253 // Note: need not to set the header actually. |
745 buf [1] = buf [3]; // V3.x |
254 converted[0] = ct_handshake; |
746 buf[2] = buf[4]; |
255 converted[1] = majorVersion; |
|
256 converted[2] = minorVersion; |
747 // header [3..4] for handshake message length |
257 // header [3..4] for handshake message length |
748 // count = 5; |
258 // required size is 5; |
749 |
259 |
750 /* |
260 /* |
751 * Store the generic V3 handshake header: 4 bytes |
261 * Store the generic V3 handshake header: 4 bytes |
752 */ |
262 */ |
753 buf [5] = 1; // HandshakeMessage.ht_client_hello |
263 converted[5] = 1; // HandshakeMessage.ht_client_hello |
754 // buf [6..8] for length of ClientHello (int24) |
264 // buf [6..8] for length of ClientHello (int24) |
755 // count += 4; |
265 // required size += 4; |
756 |
266 |
757 /* |
267 /* |
758 * ClientHello header starts with SSL version |
268 * ClientHello header starts with SSL version |
759 */ |
269 */ |
760 buf [9] = buf [1]; |
270 converted[9] = majorVersion; |
761 buf [10] = buf [2]; |
271 converted[10] = minorVersion; |
762 // count += 2; |
272 // required size += 2; |
763 count = 11; |
273 int pointer = 11; |
764 |
|
765 /* |
|
766 * Start parsing the V2 message ... |
|
767 */ |
|
768 int cipherSpecLen, sessionIdLen, nonceLen; |
|
769 |
|
770 cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff); |
|
771 sessionIdLen = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff); |
|
772 nonceLen = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff); |
|
773 |
274 |
774 /* |
275 /* |
775 * Copy Random value/nonce ... if less than the 32 bytes of |
276 * Copy Random value/nonce ... if less than the 32 bytes of |
776 * a V3 "Random", right justify and zero pad to the left. Else |
277 * a V3 "Random", right justify and zero pad to the left. Else |
777 * just take the last 32 bytes. |
278 * just take the last 32 bytes. |
778 */ |
279 */ |
779 int offset = 6 + cipherSpecLen + sessionIdLen; |
280 int offset = srcPos + 11 + cipherSpecLen + sessionIdLen; |
780 |
281 |
781 if (nonceLen < 32) { |
282 if (nonceLen < 32) { |
782 for (i = 0; i < (32 - nonceLen); i++) |
283 for (int i = 0; i < (32 - nonceLen); i++) { |
783 buf [count++] = 0; |
284 converted[pointer++] = 0; |
784 System.arraycopy(v2Msg, offset, buf, count, nonceLen); |
285 } |
785 count += nonceLen; |
286 packet.position(offset); |
|
287 packet.get(converted, pointer, nonceLen); |
|
288 |
|
289 pointer += nonceLen; |
786 } else { |
290 } else { |
787 System.arraycopy(v2Msg, offset + (nonceLen - 32), |
291 packet.position(offset + nonceLen - 32); |
788 buf, count, 32); |
292 packet.get(converted, pointer, 32); |
789 count += 32; |
293 |
790 } |
294 pointer += 32; |
791 |
295 } |
792 /* |
296 |
793 * Copy Session ID (only one byte length!) |
297 /* |
|
298 * Copy session ID (only one byte length!) |
794 */ |
299 */ |
795 offset -= sessionIdLen; |
300 offset -= sessionIdLen; |
796 buf [count++] = (byte) sessionIdLen; |
301 converted[pointer++] = (byte)(sessionIdLen & 0xFF); |
797 |
302 packet.position(offset); |
798 System.arraycopy(v2Msg, offset, buf, count, sessionIdLen); |
303 packet.get(converted, pointer, sessionIdLen); |
799 count += sessionIdLen; |
|
800 |
304 |
801 /* |
305 /* |
802 * Copy and translate cipher suites ... V2 specs with first byte zero |
306 * Copy and translate cipher suites ... V2 specs with first byte zero |
803 * are really V3 specs (in the last 2 bytes), just copy those and drop |
307 * are really V3 specs (in the last 2 bytes), just copy those and drop |
804 * the other ones. Preference order remains unchanged. |
308 * the other ones. Preference order remains unchanged. |
813 * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 |
317 * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 |
814 */ |
318 */ |
815 int j; |
319 int j; |
816 |
320 |
817 offset -= cipherSpecLen; |
321 offset -= cipherSpecLen; |
818 j = count + 2; |
322 packet.position(offset); |
819 |
323 |
820 for (i = 0; i < cipherSpecLen; i += 3) { |
324 j = pointer + 2; |
821 if (v2Msg [offset + i] != 0) |
325 for (int i = 0; i < cipherSpecLen; i += 3) { |
|
326 if (packet.get() != 0) { |
|
327 // Ignore version 2.0 specifix cipher suite. Clients |
|
328 // should also include the version 3.0 equivalent in |
|
329 // the V2ClientHello message. |
|
330 packet.get(); // ignore the 2nd byte |
|
331 packet.get(); // ignore the 3rd byte |
822 continue; |
332 continue; |
823 buf [j++] = v2Msg [offset + i + 1]; |
333 } |
824 buf [j++] = v2Msg [offset + i + 2]; |
334 |
825 } |
335 converted[j++] = packet.get(); |
826 |
336 converted[j++] = packet.get(); |
827 j -= count + 2; |
337 } |
828 buf [count++] = (byte) (j >>> 8); |
338 |
829 buf [count++] = (byte) j; |
339 j -= pointer + 2; |
830 count += j; |
340 converted[pointer++] = (byte)((j >>> 8) & 0xFF); |
|
341 converted[pointer++] = (byte)(j & 0xFF); |
|
342 pointer += j; |
831 |
343 |
832 /* |
344 /* |
833 * Append compression methods (default/null only) |
345 * Append compression methods (default/null only) |
834 */ |
346 */ |
835 buf [count++] = 1; |
347 converted[pointer++] = 1; |
836 buf [count++] = 0; // Session.compression_null |
348 converted[pointer++] = 0; // Session.compression_null |
837 |
349 |
838 /* |
350 /* |
839 * Fill in lengths of the messages we synthesized (nested: |
351 * Fill in lengths of the messages we synthesized (nested: |
840 * V3 handshake message within V3 record) and then return |
352 * V3 handshake message within V3 record). |
841 */ |
353 */ |
842 buf [3] = (byte) (count - headerSize); |
354 // Note: need not to set the header actually. |
843 buf [4] = (byte) ((count - headerSize) >>> 8); |
355 int fragLen = pointer - 5; // TLSPlaintext.length |
844 |
356 converted[3] = (byte)((fragLen >>> 8) & 0xFF); |
845 buf [headerSize + 1] = 0; |
357 converted[4] = (byte)(fragLen & 0xFF); |
846 buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8); |
358 |
847 buf [headerSize + 3] = (byte) ((count - headerSize) - 4); |
359 /* |
848 |
360 * Handshake.length, length of ClientHello message |
849 pos = headerSize; |
361 */ |
850 } |
362 fragLen = pointer - 9; // Handshake.length |
851 |
363 converted[6] = (byte)((fragLen >>> 16) & 0xFF); |
852 /** |
364 converted[7] = (byte)((fragLen >>> 8) & 0xFF); |
853 * Return a description for the given content type. This method should be |
365 converted[8] = (byte)(fragLen & 0xFF); |
854 * in Record, but since that is an interface this is not possible. |
366 |
855 * Called from InputRecord and OutputRecord. |
367 // consume the full record |
856 */ |
368 packet.position(srcPos + recordLen); |
857 static String contentName(int contentType) { |
369 |
858 switch (contentType) { |
370 // Need no header bytes. |
859 case ct_change_cipher_spec: |
371 return ByteBuffer.wrap(converted, 5, pointer - 5); // 5: header size |
860 return "Change Cipher Spec"; |
372 } |
861 case ct_alert: |
373 |
862 return "Alert"; |
374 static ByteBuffer decrypt(Authenticator authenticator, CipherBox box, |
863 case ct_handshake: |
375 byte contentType, ByteBuffer bb) throws BadPaddingException { |
864 return "Handshake"; |
376 |
865 case ct_application_data: |
377 return decrypt(authenticator, box, contentType, bb, null); |
866 return "Application Data"; |
378 } |
867 default: |
379 |
868 return "contentType = " + contentType; |
380 static ByteBuffer decrypt(Authenticator authenticator, |
869 } |
381 CipherBox box, byte contentType, ByteBuffer bb, |
870 } |
382 byte[] sequence) throws BadPaddingException { |
871 |
383 |
|
384 BadPaddingException reservedBPE = null; |
|
385 int tagLen = |
|
386 (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; |
|
387 int cipheredLength = bb.remaining(); |
|
388 int srcPos = bb.position(); |
|
389 if (!box.isNullCipher()) { |
|
390 try { |
|
391 // apply explicit nonce for AEAD/CBC cipher suites if needed |
|
392 int nonceSize = box.applyExplicitNonce( |
|
393 authenticator, contentType, bb, sequence); |
|
394 |
|
395 // decrypt the content |
|
396 if (box.isAEADMode()) { |
|
397 // DON'T decrypt the nonce_explicit for AEAD mode |
|
398 bb.position(srcPos + nonceSize); |
|
399 } // The explicit IV for CBC mode can be decrypted. |
|
400 |
|
401 // Note that the CipherBox.decrypt() does not change |
|
402 // the capacity of the buffer. |
|
403 box.decrypt(bb, tagLen); |
|
404 // We don't actually remove the nonce. |
|
405 bb.position(srcPos + nonceSize); |
|
406 } catch (BadPaddingException bpe) { |
|
407 // RFC 2246 states that decryption_failed should be used |
|
408 // for this purpose. However, that allows certain attacks, |
|
409 // so we just send bad record MAC. We also need to make |
|
410 // sure to always check the MAC to avoid a timing attack |
|
411 // for the same issue. See paper by Vaudenay et al and the |
|
412 // update in RFC 4346/5246. |
|
413 // |
|
414 // Failover to message authentication code checking. |
|
415 reservedBPE = bpe; |
|
416 } |
|
417 } |
|
418 |
|
419 // Requires message authentication code for null, stream and block |
|
420 // cipher suites. |
|
421 if ((authenticator instanceof MAC) && (tagLen != 0)) { |
|
422 MAC signer = (MAC)authenticator; |
|
423 int contentLen = bb.remaining() - tagLen; |
|
424 |
|
425 // Note that although it is not necessary, we run the same MAC |
|
426 // computation and comparison on the payload for both stream |
|
427 // cipher and CBC block cipher. |
|
428 if (contentLen < 0) { |
|
429 // negative data length, something is wrong |
|
430 if (reservedBPE == null) { |
|
431 reservedBPE = new BadPaddingException("bad record"); |
|
432 } |
|
433 |
|
434 // set offset of the dummy MAC |
|
435 contentLen = cipheredLength - tagLen; |
|
436 bb.limit(srcPos + cipheredLength); |
|
437 } |
|
438 |
|
439 // Run MAC computation and comparison on the payload. |
|
440 // |
|
441 // MAC data would be stripped off during the check. |
|
442 if (checkMacTags(contentType, bb, signer, sequence, false)) { |
|
443 if (reservedBPE == null) { |
|
444 reservedBPE = new BadPaddingException("bad record MAC"); |
|
445 } |
|
446 } |
|
447 |
|
448 // Run MAC computation and comparison on the remainder. |
|
449 // |
|
450 // It is only necessary for CBC block cipher. It is used to get a |
|
451 // constant time of MAC computation and comparison on each record. |
|
452 if (box.isCBCMode()) { |
|
453 int remainingLen = calculateRemainingLen( |
|
454 signer, cipheredLength, contentLen); |
|
455 |
|
456 // NOTE: remainingLen may be bigger (less than 1 block of the |
|
457 // hash algorithm of the MAC) than the cipheredLength. |
|
458 // |
|
459 // Is it possible to use a static buffer, rather than allocate |
|
460 // it dynamically? |
|
461 remainingLen += signer.MAClen(); |
|
462 ByteBuffer temporary = ByteBuffer.allocate(remainingLen); |
|
463 |
|
464 // Won't need to worry about the result on the remainder. And |
|
465 // then we won't need to worry about what's actual data to |
|
466 // check MAC tag on. We start the check from the header of the |
|
467 // buffer so that we don't need to construct a new byte buffer. |
|
468 checkMacTags(contentType, temporary, signer, sequence, true); |
|
469 } |
|
470 } |
|
471 |
|
472 // Is it a failover? |
|
473 if (reservedBPE != null) { |
|
474 throw reservedBPE; |
|
475 } |
|
476 |
|
477 return bb.slice(); |
|
478 } |
|
479 |
|
480 /* |
|
481 * Run MAC computation and comparison |
|
482 * |
|
483 */ |
|
484 private static boolean checkMacTags(byte contentType, ByteBuffer bb, |
|
485 MAC signer, byte[] sequence, boolean isSimulated) { |
|
486 |
|
487 int tagLen = signer.MAClen(); |
|
488 int position = bb.position(); |
|
489 int lim = bb.limit(); |
|
490 int macOffset = lim - tagLen; |
|
491 |
|
492 bb.limit(macOffset); |
|
493 byte[] hash = signer.compute(contentType, bb, sequence, isSimulated); |
|
494 if (hash == null || tagLen != hash.length) { |
|
495 // Something is wrong with MAC implementation. |
|
496 throw new RuntimeException("Internal MAC error"); |
|
497 } |
|
498 |
|
499 bb.position(macOffset); |
|
500 bb.limit(lim); |
|
501 try { |
|
502 int[] results = compareMacTags(bb, hash); |
|
503 return (results[0] != 0); |
|
504 } finally { |
|
505 // reset to the data |
|
506 bb.position(position); |
|
507 bb.limit(macOffset); |
|
508 } |
|
509 } |
|
510 |
|
511 /* |
|
512 * A constant-time comparison of the MAC tags. |
|
513 * |
|
514 * Please DON'T change the content of the ByteBuffer parameter! |
|
515 */ |
|
516 private static int[] compareMacTags(ByteBuffer bb, byte[] tag) { |
|
517 |
|
518 // An array of hits is used to prevent Hotspot optimization for |
|
519 // the purpose of a constant-time check. |
|
520 int[] results = {0, 0}; // {missed #, matched #} |
|
521 |
|
522 // The caller ensures there are enough bytes available in the buffer. |
|
523 // So we won't need to check the remaining of the buffer. |
|
524 for (int i = 0; i < tag.length; i++) { |
|
525 if (bb.get() != tag[i]) { |
|
526 results[0]++; // mismatched bytes |
|
527 } else { |
|
528 results[1]++; // matched bytes |
|
529 } |
|
530 } |
|
531 |
|
532 return results; |
|
533 } |
|
534 |
|
535 /* |
|
536 * Run MAC computation and comparison |
|
537 * |
|
538 * Please DON'T change the content of the byte buffer parameter! |
|
539 */ |
|
540 private static boolean checkMacTags(byte contentType, byte[] buffer, |
|
541 int offset, int contentLen, MAC signer, boolean isSimulated) { |
|
542 |
|
543 int tagLen = signer.MAClen(); |
|
544 byte[] hash = signer.compute( |
|
545 contentType, buffer, offset, contentLen, isSimulated); |
|
546 if (hash == null || tagLen != hash.length) { |
|
547 // Something is wrong with MAC implementation. |
|
548 throw new RuntimeException("Internal MAC error"); |
|
549 } |
|
550 |
|
551 int[] results = compareMacTags(buffer, offset + contentLen, hash); |
|
552 return (results[0] != 0); |
|
553 } |
|
554 |
|
555 /* |
|
556 * A constant-time comparison of the MAC tags. |
|
557 * |
|
558 * Please DON'T change the content of the byte buffer parameter! |
|
559 */ |
|
560 private static int[] compareMacTags( |
|
561 byte[] buffer, int offset, byte[] tag) { |
|
562 |
|
563 // An array of hits is used to prevent Hotspot optimization for |
|
564 // the purpose of a constant-time check. |
|
565 int[] results = {0, 0}; // {missed #, matched #} |
|
566 |
|
567 // The caller ensures there are enough bytes available in the buffer. |
|
568 // So we won't need to check the length of the buffer. |
|
569 for (int i = 0; i < tag.length; i++) { |
|
570 if (buffer[offset + i] != tag[i]) { |
|
571 results[0]++; // mismatched bytes |
|
572 } else { |
|
573 results[1]++; // matched bytes |
|
574 } |
|
575 } |
|
576 |
|
577 return results; |
|
578 } |
|
579 |
|
580 /* |
|
581 * Calculate the length of a dummy buffer to run MAC computation |
|
582 * and comparison on the remainder. |
|
583 * |
|
584 * The caller MUST ensure that the fullLen is not less than usedLen. |
|
585 */ |
|
586 private static int calculateRemainingLen( |
|
587 MAC signer, int fullLen, int usedLen) { |
|
588 |
|
589 int blockLen = signer.hashBlockLen(); |
|
590 int minimalPaddingLen = signer.minimalPaddingLen(); |
|
591 |
|
592 // (blockLen - minimalPaddingLen) is the maximum message size of |
|
593 // the last block of hash function operation. See FIPS 180-4, or |
|
594 // MD5 specification. |
|
595 fullLen += 13 - (blockLen - minimalPaddingLen); |
|
596 usedLen += 13 - (blockLen - minimalPaddingLen); |
|
597 |
|
598 // Note: fullLen is always not less than usedLen, and blockLen |
|
599 // is always bigger than minimalPaddingLen, so we don't worry |
|
600 // about negative values. 0x01 is added to the result to ensure |
|
601 // that the return value is positive. The extra one byte does |
|
602 // not impact the overall MAC compression function evaluations. |
|
603 return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - |
|
604 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen; |
|
605 } |
872 } |
606 } |
|
607 |