/* * 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); } } }