1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44:
45: import ;
46:
47: import ;
48: import ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54:
55: public class OutputSecurityParameters
56: {
57: private static final SystemLogger logger = SystemLogger.SYSTEM;
58: private final Cipher cipher;
59: private final Mac mac;
60: private final Deflater deflater;
61: private final SessionImpl session;
62: private final CipherSuite suite;
63: private long sequence;
64:
65: static final boolean enableCBCProtection;
66:
67: static
68: {
69: String enabled = Util.getProperty("jsse.enableCBCProtection");
70: if (enabled == null)
71: enableCBCProtection = true;
72: else
73: enableCBCProtection = Boolean.valueOf(enabled);
74: }
75:
76: public OutputSecurityParameters (final Cipher cipher, final Mac mac,
77: final Deflater deflater, SessionImpl session,
78: CipherSuite suite)
79: {
80: this.cipher = cipher;
81: this.mac = mac;
82: this.deflater = deflater;
83: this.session = session;
84: this.suite = suite;
85: sequence = 0;
86: }
87:
88:
95: public int[] encrypt (final ByteBuffer[] input, int offset, int length,
96: final ContentType contentType, final ByteBuffer output)
97: throws DataFormatException, IllegalBlockSizeException, ShortBufferException
98: {
99: if (offset < 0 || offset >= input.length
100: || length <= 0 || offset + length > input.length)
101: throw new IndexOutOfBoundsException();
102:
103: if (Debug.DEBUG)
104: for (int i = offset; i < offset+length; i++)
105: logger.logv(Component.SSL_RECORD_LAYER, "encrypting record [{0}]: {1}",
106: i-offset, input[i]);
107:
108: int maclen = 0;
109: if (mac != null)
110: maclen = session.isTruncatedMac() ? 10 : mac.getMacLength ();
111:
112: int ivlen = 0;
113: byte[] iv = null;
114: if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
115: && !suite.isStreamCipher())
116: {
117: ivlen = cipher.getBlockSize();
118: iv = new byte[ivlen];
119: session.random().nextBytes(iv);
120: }
121:
122: int padaddlen = 0;
123: if (!suite.isStreamCipher()
124: && session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
125: {
126: padaddlen = (session.random().nextInt(255 / cipher.getBlockSize())
127: * cipher.getBlockSize());
128: }
129:
130: int fragmentLength = 0;
131: ByteBuffer[] fragments = null;
132:
133: if (deflater != null)
134: {
135: ByteBufferOutputStream deflated = new ByteBufferOutputStream();
136:
137: byte[] inbuf = new byte[1024];
138: byte[] outbuf = new byte[1024];
139: int written = 0;
140:
141:
142:
143:
144: int limit = output.remaining() - (maclen + ivlen + padaddlen) - 1024;
145:
146: for (int i = offset; i < length && written < limit; i++)
147: {
148: ByteBuffer in = input[i];
149: while (in.hasRemaining() && written < limit)
150: {
151: int l = Math.min(in.remaining(), inbuf.length);
152: l = Math.min(limit - written, l);
153: in.get(inbuf, 0, l);
154: deflater.setInput(inbuf, 0, l);
155: l = deflater.deflate(outbuf);
156: deflated.write(outbuf, 0, l);
157: written += l;
158: }
159: }
160: deflater.finish();
161: while (!deflater.finished())
162: {
163: int l = deflater.deflate(outbuf);
164: deflated.write(outbuf, 0, l);
165: written += l;
166: }
167: fragments = new ByteBuffer[] { deflated.buffer() };
168: fragmentLength = ((int) deflater.getBytesWritten()) + maclen + ivlen;
169: deflater.reset();
170: offset = 0;
171: length = 1;
172: }
173: else
174: {
175: int limit = output.remaining() - (maclen + ivlen + padaddlen);
176: fragments = input;
177: for (int i = offset; i < length && fragmentLength < limit; i++)
178: {
179: int l = Math.min(limit - fragmentLength, fragments[i].remaining());
180: fragmentLength += l;
181: }
182: fragmentLength += maclen + ivlen;
183: }
184:
185:
186: int padlen = 0;
187: byte[] pad = null;
188: if (!suite.isStreamCipher())
189: {
190: int bs = cipher.getBlockSize();
191: padlen = bs - (fragmentLength % bs);
192: if (Debug.DEBUG)
193: logger.logv(Component.SSL_RECORD_LAYER,
194: "framentLen:{0} padlen:{1} blocksize:{2}",
195: fragmentLength, padlen, bs);
196: if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
197: {
198:
199:
200:
201: padlen += padaddlen;
202: while (padlen > 255)
203: padlen -= bs;
204: pad = new byte[padlen];
205: for (int i = 0; i < padlen; i++)
206: pad[i] = (byte) (padlen - 1);
207: }
208: else
209: {
210:
211:
212: pad = new byte[padlen];
213: session.random().nextBytes(pad);
214: pad[padlen - 1] = (byte) (padlen - 1);
215: }
216: fragmentLength += pad.length;
217: }
218:
219:
220: byte[] macValue = null;
221: if (mac != null)
222: {
223: mac.update((byte) (sequence >>> 56));
224: mac.update((byte) (sequence >>> 48));
225: mac.update((byte) (sequence >>> 40));
226: mac.update((byte) (sequence >>> 32));
227: mac.update((byte) (sequence >>> 24));
228: mac.update((byte) (sequence >>> 16));
229: mac.update((byte) (sequence >>> 8));
230: mac.update((byte) sequence);
231: mac.update((byte) contentType.getValue());
232: if (session.version != ProtocolVersion.SSL_3)
233: {
234: mac.update((byte) session.version.major ());
235: mac.update((byte) session.version.minor ());
236: }
237: int toWrite = fragmentLength - maclen - ivlen - padlen;
238: mac.update((byte) (toWrite >>> 8));
239: mac.update((byte) toWrite);
240: int written = 0;
241: for (int i = offset; i < length && written < toWrite; i++)
242: {
243: ByteBuffer fragment = fragments[i].duplicate();
244: int l = Math.min(fragment.remaining(), toWrite - written);
245: fragment.limit(fragment.position() + l);
246: mac.update(fragment);
247: }
248: macValue = mac.doFinal();
249: }
250:
251: Record outrecord = new Record(output);
252: outrecord.setContentType(contentType);
253: outrecord.setVersion(session.version);
254: outrecord.setLength(fragmentLength);
255:
256: int consumed = 0;
257: ByteBuffer outfragment = outrecord.fragment();
258:
259: if (cipher != null)
260: {
261: if (iv != null)
262: cipher.update(ByteBuffer.wrap(iv), outfragment);
263: int toWrite = fragmentLength - maclen - ivlen - padlen;
264: for (int i = offset; i < offset + length && consumed < toWrite; i++)
265: {
266: ByteBuffer fragment = fragments[i].slice();
267: int l = Math.min(fragment.remaining(), toWrite - consumed);
268: fragment.limit(fragment.position() + l);
269: cipher.update(fragment, outfragment);
270: fragments[i].position(fragments[i].position() + l);
271: consumed += l;
272: }
273: if (macValue != null)
274: cipher.update(ByteBuffer.wrap(macValue), outfragment);
275: if (pad != null)
276: cipher.update(ByteBuffer.wrap(pad), outfragment);
277: }
278: else
279: {
280:
281: int toWrite = fragmentLength - maclen;
282: for (int i = offset; i < offset + length && consumed < toWrite; i++)
283: {
284: ByteBuffer fragment = fragments[i];
285: int l = Math.min(fragment.remaining(), toWrite - consumed);
286: fragment.limit(fragment.position() + l);
287: outfragment.put(fragment);
288: consumed += l;
289: }
290: if (macValue != null)
291: outfragment.put(macValue);
292: }
293:
294:
295: output.position(output.position() + outrecord.length() + 5);
296: sequence++;
297:
298: return new int[] { consumed, fragmentLength + 5 };
299: }
300:
301: CipherSuite suite()
302: {
303: return suite;
304: }
305:
306: boolean needToSplitPayload()
307: {
308: return (session.version.compareTo(ProtocolVersion.TLS_1_1) < 0 &&
309: suite.isCBCMode() && enableCBCProtection);
310: }
311:
312: }