# HG changeset patch # User michaelm # Date 1319099180 -3600 # Node ID 2f0744d6ca4166603d7af34e13f832b1ae4a0184 # Parent cc353fbd6b21eb2a739c59b6be1af555102a9896# Parent a57df3d02449598a223b9c16e668567e1ba0b40a Merge diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/java/util/Collections.java --- a/jdk/src/share/classes/java/util/Collections.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/java/util/Collections.java Thu Oct 20 09:26:20 2011 +0100 @@ -2352,6 +2352,64 @@ } /** + * Returns a dynamically typesafe view of the specified queue. + * Any attempt to insert an element of the wrong type will result in + * an immediate {@link ClassCastException}. Assuming a queue contains + * no incorrectly typed elements prior to the time a dynamically typesafe + * view is generated, and that all subsequent access to the queue + * takes place through the view, it is guaranteed that the + * queue cannot contain an incorrectly typed element. + * + *

A discussion of the use of dynamically typesafe views may be + * found in the documentation for the {@link #checkedCollection + * checkedCollection} method. + * + *

The returned queue will be serializable if the specified queue + * is serializable. + * + *

Since {@code null} is considered to be a value of any reference + * type, the returned queue permits insertion of {@code null} elements + * whenever the backing queue does. + * + * @param queue the queue for which a dynamically typesafe view is to be + * returned + * @param type the type of element that {@code queue} is permitted to hold + * @return a dynamically typesafe view of the specified queue + * @since 1.8 + */ + public static Queue checkedQueue(Queue queue, Class type) { + return new CheckedQueue<>(queue, type); + } + + /** + * @serial include + */ + static class CheckedQueue + extends CheckedCollection + implements Queue, Serializable + { + private static final long serialVersionUID = 1433151992604707767L; + final Queue queue; + + CheckedQueue(Queue queue, Class elementType) { + super(queue, elementType); + this.queue = queue; + } + + public E element() {return queue.element();} + public boolean equals(Object o) {return o == this || c.equals(o);} + public int hashCode() {return c.hashCode();} + public E peek() {return queue.peek();} + public E poll() {return queue.poll();} + public E remove() {return queue.remove();} + + public boolean offer(E e) { + typeCheck(e); + return add(e); + } + } + + /** * Returns a dynamically typesafe view of the specified set. * Any attempt to insert an element of the wrong type will result in * an immediate {@link ClassCastException}. Assuming a set contains diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/pkcs/PKCS7.java --- a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java Thu Oct 20 09:26:20 2011 +0100 @@ -27,6 +27,7 @@ import java.io.*; import java.math.BigInteger; +import java.net.URI; import java.util.*; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; @@ -35,6 +36,7 @@ import java.security.cert.CertificateFactory; import java.security.*; +import sun.security.timestamp.*; import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.x509.CertificateIssuerName; @@ -68,6 +70,30 @@ private Principal[] certIssuerNames; + /* + * Random number generator for creating nonce values + */ + private static final SecureRandom RANDOM; + static { + SecureRandom tmp = null; + try { + tmp = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + // should not happen + } + RANDOM = tmp; + } + + /* + * Object identifier for the timestamping key purpose. + */ + private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8"; + + /* + * Object identifier for extendedKeyUsage extension + */ + private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; + /** * Unmarshals a PKCS7 block from its encoded form, parsing the * encoded bytes from the InputStream. @@ -733,4 +759,164 @@ public boolean isOldStyle() { return this.oldStyle; } + + /** + * Assembles a PKCS #7 signed data message that optionally includes a + * signature timestamp. + * + * @param signature the signature bytes + * @param signerChain the signer's X.509 certificate chain + * @param content the content that is signed; specify null to not include + * it in the PKCS7 data + * @param signatureAlgorithm the name of the signature algorithm + * @param tsaURI the URI of the Timestamping Authority; or null if no + * timestamp is requested + * @return the bytes of the encoded PKCS #7 signed data message + * @throws NoSuchAlgorithmException The exception is thrown if the signature + * algorithm is unrecognised. + * @throws CertificateException The exception is thrown if an error occurs + * while processing the signer's certificate or the TSA's + * certificate. + * @throws IOException The exception is thrown if an error occurs while + * generating the signature timestamp or while generating the signed + * data message. + */ + public static byte[] generateSignedData(byte[] signature, + X509Certificate[] signerChain, + byte[] content, + String signatureAlgorithm, + URI tsaURI) + throws CertificateException, IOException, NoSuchAlgorithmException + { + + // Generate the timestamp token + PKCS9Attributes unauthAttrs = null; + if (tsaURI != null) { + // Timestamp the signature + HttpTimestamper tsa = new HttpTimestamper(tsaURI); + byte[] tsToken = generateTimestampToken(tsa, signature); + + // Insert the timestamp token into the PKCS #7 signer info element + // (as an unsigned attribute) + unauthAttrs = + new PKCS9Attributes(new PKCS9Attribute[]{ + new PKCS9Attribute( + PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR, + tsToken)}); + } + + // Create the SignerInfo + X500Name issuerName = + X500Name.asX500Name(signerChain[0].getIssuerX500Principal()); + BigInteger serialNumber = signerChain[0].getSerialNumber(); + String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm); + String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm); + SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber, + AlgorithmId.get(digAlg), null, + AlgorithmId.get(encAlg), + signature, unauthAttrs); + + // Create the PKCS #7 signed data message + SignerInfo[] signerInfos = {signerInfo}; + AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()}; + // Include or exclude content + ContentInfo contentInfo = (content == null) + ? new ContentInfo(ContentInfo.DATA_OID, null) + : new ContentInfo(content); + PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo, + signerChain, signerInfos); + ByteArrayOutputStream p7out = new ByteArrayOutputStream(); + pkcs7.encodeSignedData(p7out); + + return p7out.toByteArray(); + } + + /** + * Requests, processes and validates a timestamp token from a TSA using + * common defaults. Uses the following defaults in the timestamp request: + * SHA-1 for the hash algorithm, a 64-bit nonce, and request certificate + * set to true. + * + * @param tsa the timestamping authority to use + * @param toBeTimestamped the token that is to be timestamped + * @return the encoded timestamp token + * @throws IOException The exception is thrown if an error occurs while + * communicating with the TSA. + * @throws CertificateException The exception is thrown if the TSA's + * certificate is not permitted for timestamping. + */ + private static byte[] generateTimestampToken(Timestamper tsa, + byte[] toBeTimestamped) + throws IOException, CertificateException + { + // Generate a timestamp + MessageDigest messageDigest = null; + TSRequest tsQuery = null; + try { + // SHA-1 is always used. + messageDigest = MessageDigest.getInstance("SHA-1"); + tsQuery = new TSRequest(toBeTimestamped, messageDigest); + } catch (NoSuchAlgorithmException e) { + // ignore + } + + // Generate a nonce + BigInteger nonce = null; + if (RANDOM != null) { + nonce = new BigInteger(64, RANDOM); + tsQuery.setNonce(nonce); + } + tsQuery.requestCertificate(true); + + TSResponse tsReply = tsa.generateTimestamp(tsQuery); + int status = tsReply.getStatusCode(); + // Handle TSP error + if (status != 0 && status != 1) { + throw new IOException("Error generating timestamp: " + + tsReply.getStatusCodeAsText() + " " + + tsReply.getFailureCodeAsText()); + } + PKCS7 tsToken = tsReply.getToken(); + + TimestampToken tst = tsReply.getTimestampToken(); + if (!tst.getHashAlgorithm().getName().equals("SHA")) { + throw new IOException("Digest algorithm not SHA-1 in " + + "timestamp token"); + } + if (!MessageDigest.isEqual(tst.getHashedMessage(), + tsQuery.getHashedMessage())) { + throw new IOException("Digest octets changed in timestamp token"); + } + + BigInteger replyNonce = tst.getNonce(); + if (replyNonce == null && nonce != null) { + throw new IOException("Nonce missing in timestamp token"); + } + if (replyNonce != null && !replyNonce.equals(nonce)) { + throw new IOException("Nonce changed in timestamp token"); + } + + // Examine the TSA's certificate (if present) + for (SignerInfo si: tsToken.getSignerInfos()) { + X509Certificate cert = si.getCertificate(tsToken); + if (cert == null) { + // Error, we've already set tsRequestCertificate = true + throw new CertificateException( + "Certificate not included in timestamp token"); + } else { + if (!cert.getCriticalExtensionOIDs().contains( + EXTENDED_KEY_USAGE_OID)) { + throw new CertificateException( + "Certificate is not valid for timestamping"); + } + List keyPurposes = cert.getExtendedKeyUsage(); + if (keyPurposes == null || + !keyPurposes.contains(KP_TIMESTAMPING_OID)) { + throw new CertificateException( + "Certificate is not valid for timestamping"); + } + } + } + return tsReply.getEncodedToken(); + } } diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/pkcs/SignerInfo.java --- a/jdk/src/share/classes/sun/security/pkcs/SignerInfo.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/pkcs/SignerInfo.java Thu Oct 20 09:26:20 2011 +0100 @@ -28,10 +28,14 @@ import java.io.OutputStream; import java.io.IOException; import java.math.BigInteger; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertPath; import java.security.cert.X509Certificate; import java.security.*; import java.util.ArrayList; +import sun.security.timestamp.TimestampToken; import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.x509.X500Name; @@ -51,6 +55,8 @@ AlgorithmId digestAlgorithmId; AlgorithmId digestEncryptionAlgorithmId; byte[] encryptedDigest; + Timestamp timestamp; + private boolean hasTimestamp = true; PKCS9Attributes authenticatedAttributes; PKCS9Attributes unauthenticatedAttributes; @@ -442,6 +448,62 @@ return unauthenticatedAttributes; } + /* + * Extracts a timestamp from a PKCS7 SignerInfo. + * + * Examines the signer's unsigned attributes for a + * signatureTimestampToken attribute. If present, + * then it is parsed to extract the date and time at which the + * timestamp was generated. + * + * @param info A signer information element of a PKCS 7 block. + * + * @return A timestamp token or null if none is present. + * @throws IOException if an error is encountered while parsing the + * PKCS7 data. + * @throws NoSuchAlgorithmException if an error is encountered while + * verifying the PKCS7 object. + * @throws SignatureException if an error is encountered while + * verifying the PKCS7 object. + * @throws CertificateException if an error is encountered while generating + * the TSA's certpath. + */ + public Timestamp getTimestamp() + throws IOException, NoSuchAlgorithmException, SignatureException, + CertificateException + { + if (timestamp != null || !hasTimestamp) + return timestamp; + + if (unauthenticatedAttributes == null) { + hasTimestamp = false; + return null; + } + PKCS9Attribute tsTokenAttr = + unauthenticatedAttributes.getAttribute( + PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID); + if (tsTokenAttr == null) { + hasTimestamp = false; + return null; + } + + PKCS7 tsToken = new PKCS7((byte[])tsTokenAttr.getValue()); + // Extract the content (an encoded timestamp token info) + byte[] encTsTokenInfo = tsToken.getContentInfo().getData(); + // Extract the signer (the Timestamping Authority) + // while verifying the content + SignerInfo[] tsa = tsToken.verify(encTsTokenInfo); + // Expect only one signer + ArrayList chain = tsa[0].getCertificateChain(tsToken); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath tsaChain = cf.generateCertPath(chain); + // Create a timestamp token info object + TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo); + // Create a timestamp object + timestamp = new Timestamp(tsTokenInfo.getDate(), tsaChain); + return timestamp; + } + public String toString() { HexDumpEncoder hexDump = new HexDumpEncoder(); @@ -467,5 +529,4 @@ } return out; } - } diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java --- a/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/timestamp/HttpTimestamper.java Thu Oct 20 09:26:20 2011 +0100 @@ -28,13 +28,13 @@ import java.io.BufferedInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.net.URI; import java.net.URL; import java.net.HttpURLConnection; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import sun.misc.IOUtils; +import sun.security.util.Debug; /** * A timestamper that communicates with a Timestamping Authority (TSA) @@ -58,20 +58,23 @@ private static final String TS_REPLY_MIME_TYPE = "application/timestamp-reply"; - private static final boolean DEBUG = false; + private static final Debug debug = Debug.getInstance("ts"); /* - * HTTP URL identifying the location of the TSA + * HTTP URI identifying the location of the TSA */ - private String tsaUrl = null; + private URI tsaURI = null; /** * Creates a timestamper that connects to the specified TSA. * - * @param tsa The location of the TSA. It must be an HTTP URL. + * @param tsa The location of the TSA. It must be an HTTP URI. + * @throws IllegalArgumentException if tsaURI is not an HTTP URI */ - public HttpTimestamper(String tsaUrl) { - this.tsaUrl = tsaUrl; + public HttpTimestamper(URI tsaURI) { + if (!tsaURI.getScheme().equalsIgnoreCase("http")) + throw new IllegalArgumentException("TSA must be an HTTP URI"); + this.tsaURI = tsaURI; } /** @@ -85,7 +88,7 @@ public TSResponse generateTimestamp(TSRequest tsQuery) throws IOException { HttpURLConnection connection = - (HttpURLConnection) new URL(tsaUrl).openConnection(); + (HttpURLConnection) tsaURI.toURL().openConnection(); connection.setDoOutput(true); connection.setUseCaches(false); // ignore cache connection.setRequestProperty("Content-Type", TS_QUERY_MIME_TYPE); @@ -93,15 +96,15 @@ // Avoids the "hang" when a proxy is required but none has been set. connection.setConnectTimeout(CONNECT_TIMEOUT); - if (DEBUG) { + if (debug != null) { Set>> headers = - connection.getRequestProperties().entrySet(); - System.out.println(connection.getRequestMethod() + " " + tsaUrl + + connection.getRequestProperties().entrySet(); + debug.println(connection.getRequestMethod() + " " + tsaURI + " HTTP/1.1"); - for (Map.Entry> entry : headers) { - System.out.println(" " + entry); + for (Map.Entry> e : headers) { + debug.println(" " + e); } - System.out.println(); + debug.println(); } connection.connect(); // No HTTP authentication is performed @@ -112,8 +115,8 @@ byte[] request = tsQuery.encode(); output.write(request, 0, request.length); output.flush(); - if (DEBUG) { - System.out.println("sent timestamp query (length=" + + if (debug != null) { + debug.println("sent timestamp query (length=" + request.length + ")"); } } finally { @@ -127,17 +130,17 @@ byte[] replyBuffer = null; try { input = new BufferedInputStream(connection.getInputStream()); - if (DEBUG) { + if (debug != null) { String header = connection.getHeaderField(0); - System.out.println(header); + debug.println(header); int i = 1; while ((header = connection.getHeaderField(i)) != null) { String key = connection.getHeaderFieldKey(i); - System.out.println(" " + ((key==null) ? "" : key + ": ") + + debug.println(" " + ((key==null) ? "" : key + ": ") + header); i++; } - System.out.println(); + debug.println(); } verifyMimeType(connection.getContentType()); @@ -145,8 +148,8 @@ int contentLength = connection.getContentLength(); replyBuffer = IOUtils.readFully(input, contentLength, false); - if (DEBUG) { - System.out.println("received timestamp response (length=" + + if (debug != null) { + debug.println("received timestamp response (length=" + total + ")"); } } finally { diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/timestamp/TSRequest.java --- a/jdk/src/share/classes/sun/security/timestamp/TSRequest.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/timestamp/TSRequest.java Thu Oct 20 09:26:20 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,13 @@ import java.io.IOException; import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.cert.X509Extension; import sun.security.util.DerValue; import sun.security.util.DerOutputStream; import sun.security.util.ObjectIdentifier; +import sun.security.x509.AlgorithmId; /** * This class provides a timestamp request, as defined in @@ -64,24 +67,9 @@ public class TSRequest { - private static final ObjectIdentifier SHA1_OID; - private static final ObjectIdentifier MD5_OID; - static { - ObjectIdentifier sha1 = null; - ObjectIdentifier md5 = null; - try { - sha1 = new ObjectIdentifier("1.3.14.3.2.26"); - md5 = new ObjectIdentifier("1.2.840.113549.2.5"); - } catch (IOException ioe) { - // should not happen - } - SHA1_OID = sha1; - MD5_OID = md5; - } - private int version = 1; - private ObjectIdentifier hashAlgorithmId = null; + private AlgorithmId hashAlgorithmId = null; private byte[] hashValue; @@ -94,30 +82,21 @@ private X509Extension[] extensions = null; /** - * Constructs a timestamp request for the supplied hash value.. + * Constructs a timestamp request for the supplied data. * - * @param hashValue The hash value. This is the data to be timestamped. - * @param hashAlgorithm The name of the hash algorithm. + * @param toBeTimeStamped The data to be timestamped. + * @param messageDigest The MessageDigest of the hash algorithm to use. + * @throws NoSuchAlgorithmException if the hash algorithm is not supported */ - public TSRequest(byte[] hashValue, String hashAlgorithm) { + public TSRequest(byte[] toBeTimeStamped, MessageDigest messageDigest) + throws NoSuchAlgorithmException { - // Check the common hash algorithms - if ("MD5".equalsIgnoreCase(hashAlgorithm)) { - hashAlgorithmId = MD5_OID; - // Check that the hash value matches the hash algorithm - assert hashValue.length == 16; + this.hashAlgorithmId = AlgorithmId.get(messageDigest.getAlgorithm()); + this.hashValue = messageDigest.digest(toBeTimeStamped); + } - } else if ("SHA-1".equalsIgnoreCase(hashAlgorithm) || - "SHA".equalsIgnoreCase(hashAlgorithm) || - "SHA1".equalsIgnoreCase(hashAlgorithm)) { - hashAlgorithmId = SHA1_OID; - // Check that the hash value matches the hash algorithm - assert hashValue.length == 20; - - } - // Clone the hash value - this.hashValue = new byte[hashValue.length]; - System.arraycopy(hashValue, 0, this.hashValue, 0, hashValue.length); + public byte[] getHashedMessage() { + return hashValue.clone(); } /** @@ -176,9 +155,7 @@ // encode messageImprint DerOutputStream messageImprint = new DerOutputStream(); - DerOutputStream hashAlgorithm = new DerOutputStream(); - hashAlgorithm.putOID(hashAlgorithmId); - messageImprint.write(DerValue.tag_Sequence, hashAlgorithm); + hashAlgorithmId.encode(messageImprint); messageImprint.putOctetString(hashValue); request.write(DerValue.tag_Sequence, messageImprint); diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/timestamp/TSResponse.java --- a/jdk/src/share/classes/sun/security/timestamp/TSResponse.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/timestamp/TSResponse.java Thu Oct 20 09:26:20 2011 +0100 @@ -27,6 +27,7 @@ import java.io.IOException; import sun.security.pkcs.PKCS7; +import sun.security.util.Debug; import sun.security.util.DerValue; /** @@ -175,18 +176,20 @@ */ public static final int SYSTEM_FAILURE = 25; - private static final boolean DEBUG = false; + private static final Debug debug = Debug.getInstance("ts"); private int status; private String[] statusString = null; - private int failureInfo = -1; + private boolean[] failureInfo = null; private byte[] encodedTsToken = null; private PKCS7 tsToken = null; + private TimestampToken tstInfo; + /** * Constructs an object to store the response to a timestamp request. * @@ -215,11 +218,11 @@ } /** - * Retrieve the failure code returned by the TSA. + * Retrieve the failure info returned by the TSA. * - * @return If -1 then no failure code was received. + * @return the failure info, or null if no failure code was received. */ - public int getFailureCode() { + public boolean[] getFailureInfo() { return failureInfo; } @@ -250,42 +253,38 @@ } } + private boolean isSet(int position) { + return failureInfo[position]; + } + public String getFailureCodeAsText() { - if (failureInfo == -1) { - return null; + if (failureInfo == null) { + return ""; } - switch (failureInfo) { - - case BAD_ALG: - return "Unrecognized or unsupported alrorithm identifier."; - - case BAD_REQUEST: - return "The requested transaction is not permitted or supported."; - - case BAD_DATA_FORMAT: - return "The data submitted has the wrong format."; - - case TIME_NOT_AVAILABLE: - return "The TSA's time source is not available."; + try { + if (isSet(BAD_ALG)) + return "Unrecognized or unsupported algorithm identifier."; + if (isSet(BAD_REQUEST)) + return "The requested transaction is not permitted or " + + "supported."; + if (isSet(BAD_DATA_FORMAT)) + return "The data submitted has the wrong format."; + if (isSet(TIME_NOT_AVAILABLE)) + return "The TSA's time source is not available."; + if (isSet(UNACCEPTED_POLICY)) + return "The requested TSA policy is not supported by the TSA."; + if (isSet(UNACCEPTED_EXTENSION)) + return "The requested extension is not supported by the TSA."; + if (isSet(ADD_INFO_NOT_AVAILABLE)) + return "The additional information requested could not be " + + "understood or is not available."; + if (isSet(SYSTEM_FAILURE)) + return "The request cannot be handled due to system failure."; + } catch (ArrayIndexOutOfBoundsException ex) {} - case UNACCEPTED_POLICY: - return "The requested TSA policy is not supported by the TSA."; - - case UNACCEPTED_EXTENSION: - return "The requested extension is not supported by the TSA."; - - case ADD_INFO_NOT_AVAILABLE: - return "The additional information requested could not be " + - "understood or is not available."; - - case SYSTEM_FAILURE: - return "The request cannot be handled due to system failure."; - - default: - return ("unknown status code " + status); - } + return ("unknown failure code"); } /** @@ -297,6 +296,10 @@ return tsToken; } + public TimestampToken getTimestampToken() { + return tstInfo; + } + /** * Retrieve the ASN.1 BER encoded timestamp token returned by the TSA. * @@ -323,29 +326,30 @@ // Parse status - DerValue status = derValue.data.getDerValue(); - // Parse status - this.status = status.data.getInteger(); - if (DEBUG) { - System.out.println("timestamp response: status=" + this.status); + DerValue statusInfo = derValue.data.getDerValue(); + this.status = statusInfo.data.getInteger(); + if (debug != null) { + debug.println("timestamp response: status=" + this.status); } // Parse statusString, if present - if (status.data.available() > 0) { - DerValue[] strings = status.data.getSequence(1); - statusString = new String[strings.length]; - for (int i = 0; i < strings.length; i++) { - statusString[i] = strings[i].data.getUTF8String(); + if (statusInfo.data.available() > 0) { + byte tag = (byte)statusInfo.data.peekByte(); + if (tag == DerValue.tag_SequenceOf) { + DerValue[] strings = statusInfo.data.getSequence(1); + statusString = new String[strings.length]; + for (int i = 0; i < strings.length; i++) { + statusString[i] = strings[i].getUTF8String(); + if (debug != null) { + debug.println("timestamp response: statusString=" + + statusString[i]); + } + } } } // Parse failInfo, if present - if (status.data.available() > 0) { - byte[] failInfo = status.data.getBitString(); - int failureInfo = (new Byte(failInfo[0])).intValue(); - if (failureInfo < 0 || failureInfo > 25 || failInfo.length != 1) { - throw new IOException("Bad encoding for timestamp response: " + - "unrecognized value for the failInfo element"); - } - this.failureInfo = failureInfo; + if (statusInfo.data.available() > 0) { + this.failureInfo + = statusInfo.data.getUnalignedBitString().toBooleanArray(); } // Parse timeStampToken, if present @@ -353,6 +357,7 @@ DerValue timestampToken = derValue.data.getDerValue(); encodedTsToken = timestampToken.toByteArray(); tsToken = new PKCS7(encodedTsToken); + tstInfo = new TimestampToken(tsToken.getContentInfo().getData()); } // Check the format of the timestamp response diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/tools/JarSigner.java --- a/jdk/src/share/classes/sun/security/tools/JarSigner.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java Thu Oct 20 09:26:20 2011 +0100 @@ -1277,11 +1277,10 @@ System.out.println(rb.getString("TSA.location.") + tsaUrl); } if (tsaCert != null) { - String certUrl = - TimestampedSigner.getTimestampingUrl(tsaCert); - if (certUrl != null) { + URI tsaURI = TimestampedSigner.getTimestampingURI(tsaCert); + if (tsaURI != null) { System.out.println(rb.getString("TSA.location.") + - certUrl); + tsaURI); } System.out.println(rb.getString("TSA.certificate.") + printCert("", tsaCert, false, 0, false)); diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/tools/TimestampedSigner.java --- a/jdk/src/share/classes/sun/security/tools/TimestampedSigner.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/tools/TimestampedSigner.java Thu Oct 20 09:26:20 2011 +0100 @@ -25,22 +25,14 @@ package sun.security.tools; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.math.BigInteger; import java.net.URI; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.List; import com.sun.jarsigner.*; -import java.util.Arrays; -import sun.security.pkcs.*; -import sun.security.timestamp.*; +import sun.security.pkcs.PKCS7; import sun.security.util.*; import sun.security.x509.*; @@ -57,36 +49,12 @@ public final class TimestampedSigner extends ContentSigner { /* - * Random number generator for creating nonce values - */ - private static final SecureRandom RANDOM; - static { - SecureRandom tmp = null; - try { - tmp = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - // should not happen - } - RANDOM = tmp; - } - - /* * Object identifier for the subject information access X.509 certificate * extension. */ private static final String SUBJECT_INFO_ACCESS_OID = "1.3.6.1.5.5.7.1.11"; /* - * Object identifier for the timestamping key purpose. - */ - private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8"; - - /* - * Object identifier for extendedKeyUsage extension - */ - private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; - - /* * Object identifier for the timestamping access descriptors. */ private static final ObjectIdentifier AD_TIMESTAMPING_Id; @@ -100,26 +68,6 @@ AD_TIMESTAMPING_Id = tmp; } - /* - * Location of the TSA. - */ - private String tsaUrl = null; - - /* - * TSA's X.509 certificate. - */ - private X509Certificate tsaCertificate = null; - - /* - * Generates an SHA-1 hash value for the data to be timestamped. - */ - private MessageDigest messageDigest = null; - - /* - * Parameters for the timestamping protocol. - */ - private boolean tsRequestCertificate = true; - /** * Instantiates a content signer that supports timestamped signatures. */ @@ -134,7 +82,7 @@ * and optionally the content that was signed, are packaged into a PKCS #7 * signed data message. * - * @param parameters The non-null input parameters. + * @param params The non-null input parameters. * @param omitContent true if the content should be omitted from the * signed data message. Otherwise the content is included. * @param applyTimestamp true if the signature should be timestamped. @@ -151,98 +99,41 @@ * @throws NullPointerException The exception is thrown if parameters is * null. */ - public byte[] generateSignedData(ContentSignerParameters parameters, + public byte[] generateSignedData(ContentSignerParameters params, boolean omitContent, boolean applyTimestamp) throws NoSuchAlgorithmException, CertificateException, IOException { - if (parameters == null) { + if (params == null) { throw new NullPointerException(); } - // Parse the signature algorithm to extract the digest and key - // algorithms. The expected format is: + // Parse the signature algorithm to extract the digest + // algorithm. The expected format is: // "with" // or "withand" - String signatureAlgorithm = parameters.getSignatureAlgorithm(); - String keyAlgorithm = - AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm); - String digestAlgorithm = - AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm); - AlgorithmId digestAlgorithmId = AlgorithmId.get(digestAlgorithm); + String signatureAlgorithm = params.getSignatureAlgorithm(); - // Examine signer's certificate - X509Certificate[] signerCertificateChain = - parameters.getSignerCertificateChain(); - Principal issuerName = signerCertificateChain[0].getIssuerDN(); - if (!(issuerName instanceof X500Name)) { - // must extract the original encoded form of DN for subsequent - // name comparison checks (converting to a String and back to - // an encoded DN could cause the types of String attribute - // values to be changed) - X509CertInfo tbsCert = new - X509CertInfo(signerCertificateChain[0].getTBSCertificate()); - issuerName = (Principal) - tbsCert.get(CertificateIssuerName.NAME + "." + - CertificateIssuerName.DN_NAME); - } - BigInteger serialNumber = signerCertificateChain[0].getSerialNumber(); + X509Certificate[] signerChain = params.getSignerCertificateChain(); + byte[] signature = params.getSignature(); // Include or exclude content - byte[] content = parameters.getContent(); - ContentInfo contentInfo; - if (omitContent) { - contentInfo = new ContentInfo(ContentInfo.DATA_OID, null); - } else { - contentInfo = new ContentInfo(content); - } + byte[] content = (omitContent == true) ? null : params.getContent(); - // Generate the timestamp token - byte[] signature = parameters.getSignature(); - SignerInfo signerInfo = null; + URI tsaURI = null; if (applyTimestamp) { - - tsaCertificate = parameters.getTimestampingAuthorityCertificate(); - URI tsaUri = parameters.getTimestampingAuthority(); - if (tsaUri != null) { - tsaUrl = tsaUri.toString(); - } else { + tsaURI = params.getTimestampingAuthority(); + if (tsaURI == null) { // Examine TSA cert - String certUrl = getTimestampingUrl(tsaCertificate); - if (certUrl == null) { + tsaURI = getTimestampingURI( + params.getTimestampingAuthorityCertificate()); + if (tsaURI == null) { throw new CertificateException( "Subject Information Access extension not found"); } - tsaUrl = certUrl; } - - // Timestamp the signature - byte[] tsToken = generateTimestampToken(signature); - - // Insert the timestamp token into the PKCS #7 signer info element - // (as an unsigned attribute) - PKCS9Attributes unsignedAttrs = - new PKCS9Attributes(new PKCS9Attribute[]{ - new PKCS9Attribute( - PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR, - tsToken)}); - signerInfo = new SignerInfo((X500Name)issuerName, serialNumber, - digestAlgorithmId, null, AlgorithmId.get(keyAlgorithm), - signature, unsignedAttrs); - } else { - signerInfo = new SignerInfo((X500Name)issuerName, serialNumber, - digestAlgorithmId, AlgorithmId.get(keyAlgorithm), signature); } - - SignerInfo[] signerInfos = {signerInfo}; - AlgorithmId[] algorithms = {digestAlgorithmId}; - - // Create the PKCS #7 signed data message - PKCS7 p7 = new PKCS7(algorithms, contentInfo, signerCertificateChain, - null, signerInfos); - ByteArrayOutputStream p7out = new ByteArrayOutputStream(); - p7.encodeSignedData(p7out); - - return p7out.toByteArray(); + return PKCS7.generateSignedData(signature, signerChain, content, + params.getSignatureAlgorithm(), tsaURI); } /** @@ -253,9 +144,9 @@ * accessLocation field should contain an HTTP or HTTPS URL. * * @param tsaCertificate An X.509 certificate for the TSA. - * @return An HTTP or HTTPS URL or null if none was found. + * @return An HTTP or HTTPS URI or null if none was found. */ - public static String getTimestampingUrl(X509Certificate tsaCertificate) { + public static URI getTimestampingURI(X509Certificate tsaCertificate) { if (tsaCertificate == null) { return null; @@ -282,7 +173,7 @@ uri = (URIName) location.getName(); if (uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equalsIgnoreCase("https")) { - return uri.getName(); + return uri.getURI(); } } } @@ -292,97 +183,4 @@ } return null; } - - /* - * Returns a timestamp token from a TSA for the given content. - * Performs a basic check on the token to confirm that it has been signed - * by a certificate that is permitted to sign timestamps. - * - * @param toBeTimestamped The data to be timestamped. - * @throws IOException The exception is throw if an error occurs while - * communicating with the TSA. - * @throws CertificateException The exception is throw if the TSA's - * certificate is not permitted for timestamping. - */ - private byte[] generateTimestampToken(byte[] toBeTimestamped) - throws CertificateException, IOException { - - // Generate hash value for the data to be timestamped - // SHA-1 is always used. - if (messageDigest == null) { - try { - messageDigest = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - // ignore - } - } - byte[] digest = messageDigest.digest(toBeTimestamped); - - // Generate a timestamp - TSRequest tsQuery = new TSRequest(digest, "SHA-1"); - // Generate a nonce - BigInteger nonce = null; - if (RANDOM != null) { - nonce = new BigInteger(64, RANDOM); - tsQuery.setNonce(nonce); - } - tsQuery.requestCertificate(tsRequestCertificate); - - Timestamper tsa = new HttpTimestamper(tsaUrl); // use supplied TSA - TSResponse tsReply = tsa.generateTimestamp(tsQuery); - int status = tsReply.getStatusCode(); - // Handle TSP error - if (status != 0 && status != 1) { - int failureCode = tsReply.getFailureCode(); - if (failureCode == -1) { - throw new IOException("Error generating timestamp: " + - tsReply.getStatusCodeAsText()); - } else { - throw new IOException("Error generating timestamp: " + - tsReply.getStatusCodeAsText() + " " + - tsReply.getFailureCodeAsText()); - } - } - PKCS7 tsToken = tsReply.getToken(); - - TimestampToken tst = new TimestampToken(tsToken.getContentInfo().getData()); - if (!tst.getHashAlgorithm().equals( - new AlgorithmId(new ObjectIdentifier("1.3.14.3.2.26")))) { - throw new IOException("Digest algorithm not SHA-1 in timestamp token"); - } - if (!Arrays.equals(tst.getHashedMessage(), digest)) { - throw new IOException("Digest octets changed in timestamp token"); - } - - BigInteger replyNonce = tst.getNonce(); - if (replyNonce == null && nonce != null) { - throw new IOException("Nonce missing in timestamp token"); - } - if (replyNonce != null && !replyNonce.equals(nonce)) { - throw new IOException("Nonce changed in timestamp token"); - } - - // Examine the TSA's certificate (if present) - for (SignerInfo si: tsToken.getSignerInfos()) { - X509Certificate cert = si.getCertificate(tsToken); - if (cert == null) { - // Error, we've already set tsRequestCertificate = true - throw new CertificateException( - "Certificate not included in timestamp token"); - } else { - if (!cert.getCriticalExtensionOIDs().contains( - EXTENDED_KEY_USAGE_OID)) { - throw new CertificateException( - "Certificate is not valid for timestamping"); - } - List keyPurposes = cert.getExtendedKeyUsage(); - if (keyPurposes == null || - ! keyPurposes.contains(KP_TIMESTAMPING_OID)) { - throw new CertificateException( - "Certificate is not valid for timestamping"); - } - } - } - return tsReply.getEncodedToken(); - } } diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/util/Debug.java --- a/jdk/src/share/classes/sun/security/util/Debug.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/util/Debug.java Thu Oct 20 09:26:20 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,7 @@ System.err.println("policy loading and granting"); System.err.println("provider security provider debugging"); System.err.println("scl permissions SecureClassLoader assigns"); + System.err.println("ts timestamping"); System.err.println(); System.err.println("The following can be used with access:"); System.err.println(); diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java --- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Thu Oct 20 09:21:03 2011 +0100 +++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Thu Oct 20 09:26:20 2011 +0100 @@ -35,7 +35,6 @@ import java.util.jar.*; import sun.security.pkcs.*; -import sun.security.timestamp.TimestampToken; import sun.misc.BASE64Decoder; import sun.security.jca.Providers; @@ -485,7 +484,7 @@ signers = new ArrayList(); } // Append the new code signer - signers.add(new CodeSigner(certChain, getTimestamp(info))); + signers.add(new CodeSigner(certChain, info.getTimestamp())); if (debug != null) { debug.println("Signature Block Certificate: " + @@ -500,62 +499,6 @@ } } - /* - * Examines a signature timestamp token to generate a timestamp object. - * - * Examines the signer's unsigned attributes for a - * signatureTimestampToken attribute. If present, - * then it is parsed to extract the date and time at which the - * timestamp was generated. - * - * @param info A signer information element of a PKCS 7 block. - * - * @return A timestamp token or null if none is present. - * @throws IOException if an error is encountered while parsing the - * PKCS7 data. - * @throws NoSuchAlgorithmException if an error is encountered while - * verifying the PKCS7 object. - * @throws SignatureException if an error is encountered while - * verifying the PKCS7 object. - * @throws CertificateException if an error is encountered while generating - * the TSA's certpath. - */ - private Timestamp getTimestamp(SignerInfo info) - throws IOException, NoSuchAlgorithmException, SignatureException, - CertificateException { - - Timestamp timestamp = null; - - // Extract the signer's unsigned attributes - PKCS9Attributes unsignedAttrs = info.getUnauthenticatedAttributes(); - if (unsignedAttrs != null) { - PKCS9Attribute timestampTokenAttr = - unsignedAttrs.getAttribute("signatureTimestampToken"); - if (timestampTokenAttr != null) { - PKCS7 timestampToken = - new PKCS7((byte[])timestampTokenAttr.getValue()); - // Extract the content (an encoded timestamp token info) - byte[] encodedTimestampTokenInfo = - timestampToken.getContentInfo().getData(); - // Extract the signer (the Timestamping Authority) - // while verifying the content - SignerInfo[] tsa = - timestampToken.verify(encodedTimestampTokenInfo); - // Expect only one signer - ArrayList chain = - tsa[0].getCertificateChain(timestampToken); - CertPath tsaChain = certificateFactory.generateCertPath(chain); - // Create a timestamp token info object - TimestampToken timestampTokenInfo = - new TimestampToken(encodedTimestampTokenInfo); - // Create a timestamp object - timestamp = - new Timestamp(timestampTokenInfo.getDate(), tsaChain); - } - } - return timestamp; - } - // for the toHex function private static final char[] hexc = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/test/java/net/DatagramSocket/ChangingAddress.java --- a/jdk/test/java/net/DatagramSocket/ChangingAddress.java Thu Oct 20 09:21:03 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 7084030 - * @summary Tests that DatagramSocket.getLocalAddress returns the right local - * address after connect/disconnect. - */ -import java.net.*; - -public class ChangingAddress { - - static void check(DatagramSocket ds, InetAddress expected) { - InetAddress actual = ds.getLocalAddress(); - if (!expected.equals(actual)) { - throw new RuntimeException("Expected:"+expected+" Actual"+ - actual); - } - } - - public static void main(String[] args) throws Exception { - InetAddress lh = InetAddress.getLocalHost(); - SocketAddress remote = new InetSocketAddress(lh, 1234); - InetAddress wildcard = InetAddress.getByAddress - ("localhost", new byte[]{0,0,0,0}); - try (DatagramSocket ds = new DatagramSocket()) { - check(ds, wildcard); - - ds.connect(remote); - check(ds, lh); - - ds.disconnect(); - check(ds, wildcard); - } - } -} diff -r cc353fbd6b21 -r 2f0744d6ca41 jdk/test/java/util/Collections/CheckedQueue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/Collections/CheckedQueue.java Thu Oct 20 09:26:20 2011 +0100 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5020931 + * @summary Unit test for Collections.checkedQueue + */ + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +public class CheckedQueue { + static int status = 0; + + public static void main(String[] args) throws Exception { + new CheckedQueue(); + } + + public CheckedQueue() throws Exception { + run(); + } + + private void run() throws Exception { + Method[] methods = this.getClass().getDeclaredMethods(); + + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + String methodName = method.getName(); + + if (methodName.startsWith("test")) { + try { + Object obj = method.invoke(this, new Object[0]); + } catch(Exception e) { + throw new Exception(this.getClass().getName() + "." + + methodName + " test failed, test exception " + + "follows\n" + e.getCause()); + } + } + } + } + + /** + * This test adds items to a queue. + */ + private void test00() { + int arrayLength = 10; + ArrayBlockingQueue abq = new ArrayBlockingQueue(arrayLength); + + for (int i = 0; i < arrayLength; i++) { + abq.add(new String(Integer.toString(i))); + } + } + + /** + * This test tests the CheckedQueue.add method. It creates a queue of + * {@code String}s gets the checked queue, and attempt to add an Integer to + * the checked queue. + */ + private void test01() throws Exception { + int arrayLength = 10; + ArrayBlockingQueue abq = new ArrayBlockingQueue(arrayLength + 1); + + for (int i = 0; i < arrayLength; i++) { + abq.add(new String(Integer.toString(i))); + } + + Queue q = Collections.checkedQueue(abq, String.class); + + try { + q.add(new Integer(0)); + throw new Exception(this.getClass().getName() + "." + "test01 test" + + " failed, should throw ClassCastException."); + } catch(ClassCastException cce) { + // Do nothing. + } + } + + /** + * This test tests the CheckedQueue.add method. It creates a queue of one + * {@code String}, gets the checked queue, and attempt to add an Integer to + * the checked queue. + */ + private void test02() throws Exception { + ArrayBlockingQueue abq = new ArrayBlockingQueue(1); + Queue q = Collections.checkedQueue(abq, String.class); + + try { + q.add(new Integer(0)); + throw new Exception(this.getClass().getName() + "." + "test02 test" + + " failed, should throw ClassCastException."); + } catch(ClassCastException e) { + // Do nothing. + } + } + + /** + * This test tests the Collections.checkedQueue method call for nulls in + * each and both of the parameters. + */ + private void test03() throws Exception { + ArrayBlockingQueue abq = new ArrayBlockingQueue(1); + Queue q; + + try { + q = Collections.checkedQueue(null, String.class); + throw new Exception(this.getClass().getName() + "." + "test03 test" + + " failed, should throw NullPointerException."); + } catch(NullPointerException npe) { + // Do nothing + } + + try { + q = Collections.checkedQueue(abq, null); + throw new Exception(this.getClass().getName() + "." + "test03 test" + + " failed, should throw NullPointerException."); + } catch(Exception e) { + // Do nothing + } + + try { + q = Collections.checkedQueue(null, null); + throw new Exception(this.getClass().getName() + "." + "test03 test" + + " failed, should throw NullPointerException."); + } catch(Exception e) { + // Do nothing + } + } + + /** + * This test tests the CheckedQueue.offer method. + */ + private void test04() throws Exception { + ArrayBlockingQueue abq = new ArrayBlockingQueue(1); + Queue q = Collections.checkedQueue(abq, String.class); + + try { + q.offer(null); + throw new Exception(this.getClass().getName() + "." + "test04 test" + + " failed, should throw NullPointerException."); + } catch (NullPointerException npe) { + // Do nothing + } + + try { + q.offer(new Integer(0)); + throw new Exception(this.getClass().getName() + "." + "test04 test" + + " failed, should throw ClassCastException."); + } catch (ClassCastException cce) { + // Do nothing + } + + q.offer(new String("0")); + + try { + q.offer(new String("1")); + throw new Exception(this.getClass().getName() + "." + "test04 test" + + " failed, should throw IllegalStateException."); + } catch(IllegalStateException ise) { + // Do nothing + } + } + + private void test05() { + + } +}