/* * Copyright (c) 2003, 2004, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ package sun.security.timestamp; import java.io.IOException; import java.math.BigInteger; import sun.security.pkcs.PKCS7; import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.PKCS9Attributes; import sun.security.pkcs.ParsingException; import sun.security.pkcs.SignerInfo; import sun.security.util.DerValue; import sun.security.x509.AlgorithmId; import sun.security.x509.X500Name; /** * This class provides the response corresponding to a timestamp request, * as defined in * RFC 3161. * * The TimeStampResp ASN.1 type has the following definition: *
 *
 *     TimeStampResp ::= SEQUENCE {
 *         status            PKIStatusInfo,
 *         timeStampToken    TimeStampToken OPTIONAL ]
 *
 *     PKIStatusInfo ::= SEQUENCE {
 *         status        PKIStatus,
 *         statusString  PKIFreeText OPTIONAL,
 *         failInfo      PKIFailureInfo OPTIONAL }
 *
 *     PKIStatus ::= INTEGER {
 *         granted                (0),
 *           -- when the PKIStatus contains the value zero a TimeStampToken, as
 *           -- requested, is present.
 *         grantedWithMods        (1),
 *           -- when the PKIStatus contains the value one a TimeStampToken,
 *           -- with modifications, is present.
 *         rejection              (2),
 *         waiting                (3),
 *         revocationWarning      (4),
 *           -- this message contains a warning that a revocation is
 *           -- imminent
 *         revocationNotification (5)
 *           -- notification that a revocation has occurred }
 *
 *     PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
 *           -- text encoded as UTF-8 String (note:  each UTF8String SHOULD
 *           -- include an RFC 1766 language tag to indicate the language
 *           -- of the contained text)
 *
 *     PKIFailureInfo ::= BIT STRING {
 *         badAlg              (0),
 *           -- unrecognized or unsupported Algorithm Identifier
 *         badRequest          (2),
 *           -- transaction not permitted or supported
 *         badDataFormat       (5),
 *           -- the data submitted has the wrong format
 *         timeNotAvailable    (14),
 *           -- the TSA's time source is not available
 *         unacceptedPolicy    (15),
 *           -- the requested TSA policy is not supported by the TSA
 *         unacceptedExtension (16),
 *           -- the requested extension is not supported by the TSA
 *         addInfoNotAvailable (17)
 *           -- the additional information requested could not be understood
 *           -- or is not available
 *         systemFailure       (25)
 *           -- the request cannot be handled due to system failure }
 *
 *     TimeStampToken ::= ContentInfo
 *         -- contentType is id-signedData
 *         -- content is SignedData
 *         -- eContentType within SignedData is id-ct-TSTInfo
 *         -- eContent within SignedData is TSTInfo
 *
 * 
* * @since 1.5 * @author Vincent Ryan * @see Timestamper */ public class TSResponse { // Status codes (from RFC 3161) /** * The requested timestamp was granted. */ public static final int GRANTED = 0; /** * The requested timestamp was granted with some modifications. */ public static final int GRANTED_WITH_MODS = 1; /** * The requested timestamp was not granted. */ public static final int REJECTION = 2; /** * The requested timestamp has not yet been processed. */ public static final int WAITING = 3; /** * A warning that a certificate revocation is imminent. */ public static final int REVOCATION_WARNING = 4; /** * Notification that a certificate revocation has occurred. */ public static final int REVOCATION_NOTIFICATION = 5; // Failure codes (from RFC 3161) /** * Unrecognized or unsupported algorithm identifier. */ public static final int BAD_ALG = 0; /** * The requested transaction is not permitted or supported. */ public static final int BAD_REQUEST = 2; /** * The data submitted has the wrong format. */ public static final int BAD_DATA_FORMAT = 5; /** * The TSA's time source is not available. */ public static final int TIME_NOT_AVAILABLE = 14; /** * The requested TSA policy is not supported by the TSA. */ public static final int UNACCEPTED_POLICY = 15; /** * The requested extension is not supported by the TSA. */ public static final int UNACCEPTED_EXTENSION = 16; /** * The additional information requested could not be understood or is not * available. */ public static final int ADD_INFO_NOT_AVAILABLE = 17; /** * The request cannot be handled due to system failure. */ public static final int SYSTEM_FAILURE = 25; private static final boolean DEBUG = false; private int status; private String[] statusString = null; private int failureInfo = -1; private byte[] encodedTsToken = null; private PKCS7 tsToken = null; /** * Constructs an object to store the response to a timestamp request. * * @param status A buffer containing the ASN.1 BER encoded response. * @throws IOException The exception is thrown if a problem is encountered * parsing the timestamp response. */ TSResponse(byte[] tsReply) throws IOException { parse(tsReply); } /** * Retrieve the status code returned by the TSA. */ public int getStatusCode() { return status; } /** * Retrieve the status messages returned by the TSA. * * @return If null then no status messages were received. */ public String[] getStatusMessages() { return statusString; } /** * Retrieve the failure code returned by the TSA. * * @return If -1 then no failure code was received. */ public int getFailureCode() { return failureInfo; } public String getStatusCodeAsText() { switch (status) { case GRANTED: return "the timestamp request was granted."; case GRANTED_WITH_MODS: return "the timestamp request was granted with some modifications."; case REJECTION: return "the timestamp request was rejected."; case WAITING: return "the timestamp request has not yet been processed."; case REVOCATION_WARNING: return "warning: a certificate revocation is imminent."; case REVOCATION_NOTIFICATION: return "notification: a certificate revocation has occurred."; default: return ("unknown status code " + status + "."); } } public String getFailureCodeAsText() { if (failureInfo == -1) { return null; } 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."; 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); } } /** * Retrieve the timestamp token returned by the TSA. * * @return If null then no token was received. */ public PKCS7 getToken() { return tsToken; } /** * Retrieve the ASN.1 BER encoded timestamp token returned by the TSA. * * @return If null then no token was received. */ public byte[] getEncodedToken() { return encodedTsToken; } /* * Parses the timestamp response. * * @param status A buffer containing the ASN.1 BER encoded response. * @throws IOException The exception is thrown if a problem is encountered * parsing the timestamp response. */ private void parse(byte[] tsReply) throws IOException { // Decode TimeStampResp DerValue derValue = new DerValue(tsReply); if (derValue.tag != DerValue.tag_Sequence) { throw new IOException("Bad encoding for timestamp response"); } // Parse status DerValue status = derValue.data.getDerValue(); // Parse status this.status = status.data.getInteger(); if (DEBUG) { System.out.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].getUTF8String(); } } // 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; } // Parse timeStampToken, if present if (derValue.data.available() > 0) { DerValue timestampToken = derValue.data.getDerValue(); encodedTsToken = timestampToken.toByteArray(); tsToken = new PKCS7(encodedTsToken); } // Check the format of the timestamp response if (this.status == 0 || this.status == 1) { if (tsToken == null) { throw new TimestampException( "Bad encoding for timestamp response: " + "expected a timeStampToken element to be present"); } } else if (tsToken != null) { throw new TimestampException( "Bad encoding for timestamp response: " + "expected no timeStampToken element to be present"); } } final static class TimestampException extends IOException { TimestampException(String message) { super(message); } } }