summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/net/RoughtimeClient.java499
1 files changed, 0 insertions, 499 deletions
diff --git a/core/java/android/net/RoughtimeClient.java b/core/java/android/net/RoughtimeClient.java
deleted file mode 100644
index cf4d8a2d3f5a..000000000000
--- a/core/java/android/net/RoughtimeClient.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-
-/**
- * {@hide}
- *
- * Simple Roughtime client class for retrieving network time.
- */
-public class RoughtimeClient
-{
- private static final String TAG = "RoughtimeClient";
- private static final boolean ENABLE_DEBUG = true;
-
- private static final int ROUGHTIME_PORT = 5333;
-
- private static final int MIN_REQUEST_SIZE = 1024;
-
- private static final int NONCE_SIZE = 64;
-
- private static final int MAX_DATAGRAM_SIZE = 65507;
-
- private final SecureRandom random = new SecureRandom();
-
- /**
- * Tag values. Exposed for use in tests only.
- */
- protected static enum Tag {
- /**
- * Nonce used to initiate a transaction.
- */
- NONC(0x434e4f4e),
-
- /**
- * Signed portion of a response.
- **/
- SREP(0x50455253),
-
- /**
- * Pad data. Always the largest tag lexicographically.
- */
- PAD(0xff444150),
-
- /**
- * A signature for a neighboring SREP.
- */
- SIG(0x474953),
-
- /**
- * Server certificate.
- */
- CERT(0x54524543),
-
- /**
- * Position in the Merkle tree.
- */
- INDX(0x58444e49),
-
- /**
- * Upward path in the Merkle tree.
- */
- PATH(0x48544150),
-
- /**
- * Midpoint of the time interval in the response.
- */
- MIDP(0x5044494d),
-
- /**
- * Radius of the time interval in the response.
- */
- RADI(0x49444152),
-
- /**
- * Root of the Merkle tree.
- */
- ROOT(0x544f4f52),
-
- /**
- * Delegation from the long term key to an online key.
- */
- DELE(0x454c4544),
-
- /**
- * Online public key.
- */
- PUBK(0x4b425550),
-
- /**
- * Earliest midpoint time the given PUBK can authenticate.
- */
- MINT(0x544e494d),
-
- /**
- * Latest midpoint time the given PUBK can authenticate.
- */
- MAXT(0x5458414d);
-
- private final int value;
-
- Tag(int value) {
- this.value = value;
- }
-
- private int value() {
- return value;
- }
- }
-
- /**
- * A result retrieved from a roughtime server.
- */
- private static class Result {
- public long midpoint;
- public int radius;
- public long collectionTime;
- }
-
- /**
- * A Roughtime protocol message. Functionally a serializable map from Tags
- * to byte arrays.
- */
- protected static class Message {
- private HashMap<Integer,byte[]> items = new HashMap<Integer,byte[]>();
- public int padSize = 0;
-
- public Message() {}
-
- /**
- * Set the given data for the given tag.
- */
- public void put(Tag tag, byte[] data) {
- put(tag.value(), data);
- }
-
- private void put(int tag, byte[] data) {
- items.put(tag, data);
- }
-
- /**
- * Get the data associated with the given tag.
- */
- public byte[] get(Tag tag) {
- return items.get(tag.value());
- }
-
- /**
- * Get the data associated with the given tag and decode it as a 64-bit
- * integer.
- */
- public long getLong(Tag tag) {
- ByteBuffer b = ByteBuffer.wrap(get(tag));
- return b.getLong();
- }
-
- /**
- * Get the data associated with the given tag and decode it as a 32-bit
- * integer.
- */
- public int getInt(Tag tag) {
- ByteBuffer b = ByteBuffer.wrap(get(tag));
- return b.getInt();
- }
-
- /**
- * Encode the given long value as a 64-bit little-endian value and
- * associate it with the given tag.
- */
- public void putLong(Tag tag, long l) {
- ByteBuffer b = ByteBuffer.allocate(8);
- b.putLong(l);
- put(tag, b.array());
- }
-
- /**
- * Encode the given int value as a 32-bit little-endian value and
- * associate it with the given tag.
- */
- public void putInt(Tag tag, int l) {
- ByteBuffer b = ByteBuffer.allocate(4);
- b.putInt(l);
- put(tag, b.array());
- }
-
- /**
- * Get a packed representation of this message suitable for the wire.
- */
- public byte[] serialize() {
- if (items.size() == 0) {
- if (padSize > 4)
- return new byte[padSize];
- else
- return new byte[4];
- }
-
- int size = 0;
-
- ArrayList<Integer> offsets = new ArrayList<Integer>();
- ArrayList<Integer> tagList = new ArrayList<Integer>(items.keySet());
- Collections.sort(tagList);
-
- boolean first = true;
- for (int tag : tagList) {
- if (! first) {
- offsets.add(size);
- }
-
- first = false;
- size += items.get(tag).length;
- }
-
- ByteBuffer dataBuf = ByteBuffer.allocate(size);
- dataBuf.order(ByteOrder.LITTLE_ENDIAN);
-
- int valueDataSize = size;
- size += 4 + offsets.size() * 4 + tagList.size() * 4;
-
- int tagCount = items.size();
-
- if (size < padSize) {
- offsets.add(valueDataSize);
- tagList.add(Tag.PAD.value());
-
- if (size + 8 > padSize) {
- size = size + 8;
- } else {
- size = padSize;
- }
-
- tagCount += 1;
- }
-
- ByteBuffer buf = ByteBuffer.allocate(size);
- buf.order(ByteOrder.LITTLE_ENDIAN);
- buf.putInt(tagCount);
-
- for (int offset : offsets) {
- buf.putInt(offset);
- }
-
- for (int tag : tagList) {
- buf.putInt(tag);
-
- if (tag != Tag.PAD.value()) {
- dataBuf.put(items.get(tag));
- }
- }
-
- buf.put(dataBuf.array());
-
- return buf.array();
- }
-
- /**
- * Given a byte stream from the wire, unpack it into a Message object.
- */
- public static Message deserialize(byte[] data) {
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
- Message msg = new Message();
-
- int count = buf.getInt();
-
- if (count == 0) {
- return msg;
- }
-
- ArrayList<Integer> offsets = new ArrayList<Integer>();
- offsets.add(0);
-
- for (int i = 1; i < count; i++) {
- offsets.add(buf.getInt());
- }
-
- ArrayList<Integer> tags = new ArrayList<Integer>();
- for (int i = 0; i < count; i++) {
- int tag = buf.getInt();
- tags.add(tag);
- }
-
- offsets.add(buf.remaining());
-
- for (int i = 0; i < count; i++) {
- int tag = tags.get(i);
- int start = offsets.get(i);
- int end = offsets.get(i+1);
- byte[] content = new byte[end - start];
-
- buf.get(content);
- if (tag != Tag.PAD.value()) {
- msg.put(tag, content);
- }
- }
-
- return msg;
- }
-
- /**
- * Send this message over the given socket to the given address and port.
- */
- public void send(DatagramSocket socket, InetAddress address, int port)
- throws IOException {
- byte[] buffer = serialize();
- DatagramPacket message = new DatagramPacket(buffer, buffer.length,
- address, port);
- socket.send(message);
- }
-
- /**
- * Receive a Message object from the given socket.
- */
- public static Message receive(DatagramSocket socket)
- throws IOException {
- byte[] buffer = new byte[MAX_DATAGRAM_SIZE];
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
-
- socket.receive(packet);
-
- return deserialize(Arrays.copyOf(buffer, packet.getLength()));
- }
- }
-
- private MessageDigest messageDigest = null;
-
- private final ArrayList<Result> results = new ArrayList<Result>();
- private long lastRequest = 0;
-
- private Message createRequestMessage() {
- byte[] nonce = new byte[NONCE_SIZE];
- random.nextBytes(nonce); // TODO: Chain nonces
-
- assert nonce.length == NONCE_SIZE :
- "Nonce must be " + NONCE_SIZE + " bytes.";
-
- Message msg = new Message();
-
- msg.put(Tag.NONC, nonce);
- msg.padSize = MIN_REQUEST_SIZE;
-
- return msg;
- }
-
- /**
- * Contact the Roughtime server at the given address and port and collect a
- * result time to add to our collection.
- *
- * @param host host name of the server.
- * @param timeout network timeout in milliseconds.
- * @return true if the transaction was successful.
- */
- public boolean requestTime(String host, int timeout) {
- InetAddress address = null;
- try {
- address = InetAddress.getByName(host);
- } catch (Exception e) {
- if (ENABLE_DEBUG) {
- Log.d(TAG, "request time failed", e);
- }
-
- return false;
- }
- return requestTime(address, ROUGHTIME_PORT, timeout);
- }
-
- /**
- * Contact the Roughtime server at the given address and port and collect a
- * result time to add to our collection.
- *
- * @param address address for the server.
- * @param port port to talk to the server on.
- * @param timeout network timeout in milliseconds.
- * @return true if the transaction was successful.
- */
- public boolean requestTime(InetAddress address, int port, int timeout) {
-
- final long rightNow = SystemClock.elapsedRealtime();
-
- if ((rightNow - lastRequest) > timeout) {
- results.clear();
- }
-
- lastRequest = rightNow;
-
- DatagramSocket socket = null;
- try {
- if (messageDigest == null) {
- messageDigest = MessageDigest.getInstance("SHA-512");
- }
-
- socket = new DatagramSocket();
- socket.setSoTimeout(timeout);
- final long startTime = SystemClock.elapsedRealtime();
- Message request = createRequestMessage();
- request.send(socket, address, port);
- final long endTime = SystemClock.elapsedRealtime();
- Message response = Message.receive(socket);
- byte[] signedData = response.get(Tag.SREP);
- Message signedResponse = Message.deserialize(signedData);
-
- final Result result = new Result();
- result.midpoint = signedResponse.getLong(Tag.MIDP);
- result.radius = signedResponse.getInt(Tag.RADI);
- result.collectionTime = (startTime + endTime) / 2;
-
- final byte[] root = signedResponse.get(Tag.ROOT);
- final byte[] path = response.get(Tag.PATH);
- final byte[] nonce = request.get(Tag.NONC);
- final int index = response.getInt(Tag.INDX);
-
- if (! verifyNonce(root, path, nonce, index)) {
- Log.w(TAG, "failed to authenticate roughtime response.");
- return false;
- }
-
- results.add(result);
- } catch (Exception e) {
- if (ENABLE_DEBUG) {
- Log.d(TAG, "request time failed", e);
- }
-
- return false;
- } finally {
- if (socket != null) {
- socket.close();
- }
- }
-
- return true;
- }
-
- /**
- * Verify that a reply message corresponds to the nonce sent in the request.
- *
- * @param root Root of the Merkle tree used to sign the nonce. Received in
- * the ROOT tag of the reply.
- * @param path Sibling hashes along the path to the root of the Merkle tree.
- * Received in the PATH tag of the reply.
- * @param nonce The nonce we sent in the request.
- * @param index Bitfield indicating whether chunks of the path are left or
- * right children.
- * @return true if the verification is successful.
- */
- private boolean verifyNonce(byte[] root, byte[] path, byte[] nonce,
- int index) {
- messageDigest.update(new byte[]{ 0 });
- byte[] hash = messageDigest.digest(nonce);
- int pos = 0;
- byte[] one = new byte[]{ 1 };
-
- while (pos < path.length) {
- messageDigest.update(one);
-
- if ((index&1) != 0) {
- messageDigest.update(path, pos, 64);
- hash = messageDigest.digest(hash);
- } else {
- messageDigest.update(hash);
- messageDigest.update(path, pos, 64);
- hash = messageDigest.digest();
- }
-
- pos += 64;
- index >>>= 1;
- }
-
- return Arrays.equals(root, hash);
- }
-}