4567N/A/*
4567N/A * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
4567N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4567N/A *
4567N/A * This code is free software; you can redistribute it and/or modify it
4567N/A * under the terms of the GNU General Public License version 2 only, as
4567N/A * published by the Free Software Foundation. Oracle designates this
4567N/A * particular file as subject to the "Classpath" exception as provided
4567N/A * by Oracle in the LICENSE file that accompanied this code.
4567N/A *
4567N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4567N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4567N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4567N/A * version 2 for more details (a copy is included in the LICENSE file that
4567N/A * accompanied this code).
4567N/A *
4567N/A * You should have received a copy of the GNU General Public License version
4567N/A * 2 along with this work; if not, write to the Free Software Foundation,
4567N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4567N/A *
4567N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4567N/A * or visit www.oracle.com if you need additional information or have any
4567N/A * questions.
4567N/A */
4567N/A
4567N/Apackage sun.security.timestamp;
4567N/A
4567N/Aimport java.io.BufferedInputStream;
4567N/Aimport java.io.DataOutputStream;
4567N/Aimport java.io.IOException;
4567N/Aimport java.net.URL;
4567N/Aimport java.net.HttpURLConnection;
4567N/Aimport java.util.Iterator;
4567N/Aimport java.util.Set;
4567N/Aimport java.util.Arrays;
4567N/A
4567N/Aimport sun.misc.IOUtils;
4567N/Aimport sun.security.pkcs.*;
4567N/A
4567N/A/**
4567N/A * A timestamper that communicates with a Timestamping Authority (TSA)
4567N/A * over HTTP.
4567N/A * It supports the Time-Stamp Protocol defined in:
4567N/A * <a href="http://www.ietf.org/rfc/rfc3161.txt">RFC 3161</a>.
4567N/A *
4567N/A * @since 1.5
4567N/A * @author Vincent Ryan
4567N/A */
4567N/A
4567N/Apublic class HttpTimestamper implements Timestamper {
4567N/A
4567N/A private static final int CONNECT_TIMEOUT = 15000; // 15 seconds
4567N/A
4567N/A // The MIME type for a timestamp query
4567N/A private static final String TS_QUERY_MIME_TYPE =
4567N/A "application/timestamp-query";
4567N/A
4567N/A // The MIME type for a timestamp reply
4567N/A private static final String TS_REPLY_MIME_TYPE =
4567N/A "application/timestamp-reply";
4567N/A
4567N/A private static final boolean DEBUG = false;
4567N/A
4567N/A /*
4567N/A * HTTP URL identifying the location of the TSA
4567N/A */
4567N/A private String tsaUrl = null;
4567N/A
4567N/A /**
4567N/A * Creates a timestamper that connects to the specified TSA.
4567N/A *
4567N/A * @param tsa The location of the TSA. It must be an HTTP URL.
4567N/A */
4567N/A public HttpTimestamper(String tsaUrl) {
4567N/A this.tsaUrl = tsaUrl;
4567N/A }
4567N/A
4567N/A /**
4567N/A * Connects to the TSA and requests a timestamp.
4567N/A *
4567N/A * @param tsQuery The timestamp query.
4567N/A * @return The result of the timestamp query.
4567N/A * @throws IOException The exception is thrown if a problem occurs while
4567N/A * communicating with the TSA.
4567N/A */
4567N/A public TSResponse generateTimestamp(TSRequest tsQuery) throws IOException {
4567N/A
4567N/A HttpURLConnection connection =
4567N/A (HttpURLConnection) new URL(tsaUrl).openConnection();
4567N/A connection.setDoOutput(true);
4567N/A connection.setUseCaches(false); // ignore cache
4567N/A connection.setRequestProperty("Content-Type", TS_QUERY_MIME_TYPE);
4567N/A connection.setRequestMethod("POST");
4567N/A // Avoids the "hang" when a proxy is required but none has been set.
4567N/A connection.setConnectTimeout(CONNECT_TIMEOUT);
4567N/A
4567N/A if (DEBUG) {
4567N/A Set headers = connection.getRequestProperties().entrySet();
4567N/A System.out.println(connection.getRequestMethod() + " " + tsaUrl +
4567N/A " HTTP/1.1");
4567N/A for (Iterator i = headers.iterator(); i.hasNext(); ) {
4567N/A System.out.println(" " + i.next());
4567N/A }
4567N/A System.out.println();
4567N/A }
4567N/A connection.connect(); // No HTTP authentication is performed
4567N/A
4567N/A // Send the request
4567N/A DataOutputStream output = null;
4567N/A try {
4567N/A output = new DataOutputStream(connection.getOutputStream());
4567N/A byte[] request = tsQuery.encode();
4567N/A output.write(request, 0, request.length);
4567N/A output.flush();
4567N/A if (DEBUG) {
4567N/A System.out.println("sent timestamp query (length=" +
4567N/A request.length + ")");
4567N/A }
4567N/A } finally {
4567N/A if (output != null) {
4567N/A output.close();
4567N/A }
4567N/A }
4567N/A
4567N/A // Receive the reply
4567N/A BufferedInputStream input = null;
4567N/A byte[] replyBuffer = null;
4567N/A try {
4567N/A input = new BufferedInputStream(connection.getInputStream());
4567N/A if (DEBUG) {
4567N/A String header = connection.getHeaderField(0);
4567N/A System.out.println(header);
4567N/A int i = 1;
4567N/A while ((header = connection.getHeaderField(i)) != null) {
4567N/A String key = connection.getHeaderFieldKey(i);
4567N/A System.out.println(" " + ((key==null) ? "" : key + ": ") +
4567N/A header);
4567N/A i++;
4567N/A }
4567N/A System.out.println();
4567N/A }
4567N/A verifyMimeType(connection.getContentType());
4567N/A
4567N/A int total = 0;
4567N/A int contentLength = connection.getContentLength();
4567N/A replyBuffer = IOUtils.readFully(input, contentLength, false);
4567N/A
4567N/A if (DEBUG) {
4567N/A System.out.println("received timestamp response (length=" +
total + ")");
}
} finally {
if (input != null) {
input.close();
}
}
return new TSResponse(replyBuffer);
}
/*
* Checks that the MIME content type is a timestamp reply.
*
* @param contentType The MIME content type to be checked.
* @throws IOException The exception is thrown if a mismatch occurs.
*/
private static void verifyMimeType(String contentType) throws IOException {
if (! TS_REPLY_MIME_TYPE.equalsIgnoreCase(contentType)) {
throw new IOException("MIME Content-Type is not " +
TS_REPLY_MIME_TYPE);
}
}
}