|
1 /* |
|
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * @test |
|
26 * @bug 8043758 |
|
27 * @summary Testing DTLS records sequence number property support in application |
|
28 * data exchange. |
|
29 * @key randomness |
|
30 * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon |
|
31 * @run main/othervm -Dtest.security.protocol=DTLS |
|
32 * -Dtest.mode=norm DTLSSequenceNumberTest |
|
33 * @run main/othervm -Dtest.security.protocol=DTLS |
|
34 * -Dtest.mode=norm_sni DTLSSequenceNumberTest |
|
35 * @run main/othervm -Dtest.security.protocol=DTLS |
|
36 * -Dtest.mode=krb DTLSSequenceNumberTest |
|
37 */ |
|
38 |
|
39 import java.nio.ByteBuffer; |
|
40 import java.util.TreeMap; |
|
41 import javax.net.ssl.SSLContext; |
|
42 import javax.net.ssl.SSLEngine; |
|
43 import javax.net.ssl.SSLEngineResult; |
|
44 import javax.net.ssl.SSLException; |
|
45 import java.util.Random; |
|
46 import jdk.testlibrary.RandomFactory; |
|
47 |
|
48 /** |
|
49 * Testing DTLS records sequence number property support in application data |
|
50 * exchange. |
|
51 */ |
|
52 public class DTLSSequenceNumberTest extends SSLEngineTestCase { |
|
53 |
|
54 private final String BIG_MESSAGE = "Very very big message. One two three" |
|
55 + " four five six seven eight nine ten eleven twelve thirteen" |
|
56 + " fourteen fifteen sixteen seventeen eighteen nineteen twenty."; |
|
57 private final byte[] BIG_MESSAGE_BYTES = BIG_MESSAGE.getBytes(); |
|
58 private final int PIECES_NUMBER = 15; |
|
59 |
|
60 public static void main(String[] args) { |
|
61 DTLSSequenceNumberTest test = new DTLSSequenceNumberTest(); |
|
62 setUpAndStartKDCIfNeeded(); |
|
63 test.runTests(); |
|
64 } |
|
65 |
|
66 @Override |
|
67 protected void testOneCipher(String cipher) throws SSLException { |
|
68 SSLContext context = getContext(); |
|
69 int maxPacketSize = getMaxPacketSize(); |
|
70 boolean useSNI = !TEST_MODE.equals("norm"); |
|
71 SSLEngine clientEngine = getClientSSLEngine(context, useSNI); |
|
72 SSLEngine serverEngine = getServerSSLEngine(context, useSNI); |
|
73 clientEngine.setEnabledCipherSuites(new String[]{cipher}); |
|
74 serverEngine.setEnabledCipherSuites(new String[]{cipher}); |
|
75 serverEngine.setNeedClientAuth(!cipher.contains("anon")); |
|
76 doHandshake(clientEngine, serverEngine, maxPacketSize, |
|
77 HandshakeMode.INITIAL_HANDSHAKE); |
|
78 checkSeqNumPropertyWithAppDataSend(clientEngine, serverEngine); |
|
79 checkSeqNumPropertyWithAppDataSend(serverEngine, clientEngine); |
|
80 } |
|
81 |
|
82 private void checkSeqNumPropertyWithAppDataSend(SSLEngine sendEngine, |
|
83 SSLEngine recvEngine) throws SSLException { |
|
84 String sender, reciever; |
|
85 if (sendEngine.getUseClientMode() && !recvEngine.getUseClientMode()) { |
|
86 sender = "Client"; |
|
87 reciever = "Server"; |
|
88 } else if (recvEngine.getUseClientMode() && !sendEngine.getUseClientMode()) { |
|
89 sender = "Server"; |
|
90 reciever = "Client"; |
|
91 } else { |
|
92 throw new Error("Both engines are in the same mode"); |
|
93 } |
|
94 System.out.println("=================================================" |
|
95 + "==========="); |
|
96 System.out.println("Checking DTLS sequence number support" |
|
97 + " by sending data from " + sender + " to " + reciever); |
|
98 ByteBuffer[] sentMessages = new ByteBuffer[PIECES_NUMBER]; |
|
99 ByteBuffer[] netBuffers = new ByteBuffer[PIECES_NUMBER]; |
|
100 TreeMap<Long, ByteBuffer> recvMap = new TreeMap<>(Long::compareUnsigned); |
|
101 int symbolsInAMessage; |
|
102 int symbolsInTheLastMessage; |
|
103 int[] recievingSequence = new int[PIECES_NUMBER]; |
|
104 for (int i = 0; i < PIECES_NUMBER; i++) { |
|
105 recievingSequence[i] = i; |
|
106 } |
|
107 shuffleArray(recievingSequence); |
|
108 if (BIG_MESSAGE.length() % PIECES_NUMBER == 0) { |
|
109 symbolsInAMessage = BIG_MESSAGE.length() / PIECES_NUMBER; |
|
110 symbolsInTheLastMessage = symbolsInAMessage; |
|
111 } else { |
|
112 symbolsInAMessage = BIG_MESSAGE.length() / (PIECES_NUMBER - 1); |
|
113 symbolsInTheLastMessage = BIG_MESSAGE.length() % (PIECES_NUMBER - 1); |
|
114 } |
|
115 for (int i = 0; i < PIECES_NUMBER - 1; i++) { |
|
116 sentMessages[i] = ByteBuffer.wrap(BIG_MESSAGE_BYTES, |
|
117 i * symbolsInAMessage, symbolsInAMessage); |
|
118 } |
|
119 sentMessages[PIECES_NUMBER - 1] = ByteBuffer.wrap(BIG_MESSAGE_BYTES, |
|
120 (PIECES_NUMBER - 1) * symbolsInAMessage, symbolsInTheLastMessage); |
|
121 long prevSeqNum = 0L; |
|
122 //Wrapping massages in direct order |
|
123 for (int i = 0; i < PIECES_NUMBER; i++) { |
|
124 netBuffers[i] = ByteBuffer.allocate(sendEngine.getSession() |
|
125 .getPacketBufferSize()); |
|
126 SSLEngineResult[] r = new SSLEngineResult[1]; |
|
127 netBuffers[i] = doWrap(sendEngine, sender, 0, sentMessages[i], r); |
|
128 long seqNum = r[0].sequenceNumber(); |
|
129 if (Long.compareUnsigned(seqNum, prevSeqNum) <= 0) { |
|
130 throw new AssertionError("Sequence number of the wrapped " |
|
131 + "message is less or equal than that of the" |
|
132 + " previous one! " |
|
133 + "Was " + prevSeqNum + ", now " + seqNum + "."); |
|
134 } |
|
135 prevSeqNum = seqNum; |
|
136 } |
|
137 //Unwrapping messages in random order and trying to reconstruct order |
|
138 //from sequence number. |
|
139 for (int i = 0; i < PIECES_NUMBER; i++) { |
|
140 int recvNow = recievingSequence[i]; |
|
141 SSLEngineResult[] r = new SSLEngineResult[1]; |
|
142 ByteBuffer recvMassage = doUnWrap(recvEngine, reciever, |
|
143 netBuffers[recvNow], r); |
|
144 long seqNum = r[0].sequenceNumber(); |
|
145 recvMap.put(seqNum, recvMassage); |
|
146 } |
|
147 int mapSize = recvMap.size(); |
|
148 if (mapSize != PIECES_NUMBER) { |
|
149 throw new AssertionError("The number of received massages " |
|
150 + mapSize + " is not equal to the number of sent messages " |
|
151 + PIECES_NUMBER + "!"); |
|
152 } |
|
153 byte[] recvBigMsgBytes = new byte[BIG_MESSAGE_BYTES.length]; |
|
154 int counter = 0; |
|
155 for (ByteBuffer msg : recvMap.values()) { |
|
156 System.arraycopy(msg.array(), 0, recvBigMsgBytes, |
|
157 counter * symbolsInAMessage, msg.remaining()); |
|
158 counter++; |
|
159 } |
|
160 String recvBigMsg = new String(recvBigMsgBytes); |
|
161 if (!recvBigMsg.equals(BIG_MESSAGE)) { |
|
162 throw new AssertionError("Received big message is not equal to" |
|
163 + " one that was sent! Received message is: " + recvBigMsg); |
|
164 } |
|
165 } |
|
166 |
|
167 private static void shuffleArray(int[] ar) { |
|
168 final Random RNG = RandomFactory.getRandom(); |
|
169 for (int i = ar.length - 1; i > 0; i--) { |
|
170 int index = RNG.nextInt(i + 1); |
|
171 int a = ar[index]; |
|
172 ar[index] = ar[i]; |
|
173 ar[i] = a; |
|
174 } |
|
175 } |
|
176 } |