TSAClientBouncyCastle.java

1
/*
2
 * $Id: TSAClientBouncyCastle.java 4065 2009-09-16 23:09:11Z psoares33 $
3
 *
4
 * Copyright 2009 Martin Brunecky, Aiken Sam
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * (the "License"); you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the License.
13
 *
14
 * The Original Code is 'iText, a free JAVA-PDF library'.
15
 *
16
 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17
 * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie.
18
 * All Rights Reserved.
19
 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20
 * are Copyright (C) 2009 by Martin Brunecky. All Rights Reserved.
21
 *
22
 * Contributor(s): all the names of the contributors are added in the source code
23
 * where applicable.
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of the
26
 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27
 * provisions of LGPL are applicable instead of those above.  If you wish to
28
 * allow use of your version of this file only under the terms of the LGPL
29
 * License and not to allow others to use your version of this file under
30
 * the MPL, indicate your decision by deleting the provisions above and
31
 * replace them with the notice and other provisions required by the LGPL.
32
 * If you do not delete the provisions above, a recipient may use your version
33
 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34
 *
35
 * This library is free software; you can redistribute it and/or modify it
36
 * under the terms of the MPL as stated above or under the terms of the GNU
37
 * Library General Public License as published by the Free Software Foundation;
38
 * either version 2 of the License, or any later version.
39
 *
40
 * This library is distributed in the hope that it will be useful, but WITHOUT
41
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42
 * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43
 * details.
44
 *
45
 * If you didn't download this code from the following link, you should check if
46
 * you aren't using an obsolete version:
47
 * http://www.lowagie.com/iText/
48
 */
49
50
package com.lowagie.text.pdf;
51
52
import java.io.ByteArrayOutputStream;
53
import java.io.InputStream;
54
import java.io.OutputStream;
55
import java.math.BigInteger;
56
import java.net.URL;
57
import java.net.URLConnection;
58
import java.util.Base64;
59
60
import org.bouncycastle.asn1.cmp.PKIFailureInfo;
61
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
62
import org.bouncycastle.tsp.TimeStampRequest;
63
import org.bouncycastle.tsp.TimeStampRequestGenerator;
64
import org.bouncycastle.tsp.TimeStampResponse;
65
import org.bouncycastle.tsp.TimeStampToken;
66
import org.bouncycastle.tsp.TimeStampTokenInfo;
67
68
import com.lowagie.text.error_messages.MessageLocalization;
69
70
/**
71
 * Time Stamp Authority Client interface implementation using Bouncy Castle
72
 * org.bouncycastle.tsp package.
73
 * <p>
74
 * Created by Aiken Sam, 2006-11-15, refactored by Martin Brunecky, 07/15/2007
75
 * for ease of subclassing.
76
 * </p>
77
 * 
78
 * @since 2.1.6
79
 */
80
public class TSAClientBouncyCastle implements TSAClient {
81
  /** URL of the Time Stamp Authority */
82
  protected String tsaURL;
83
  /** TSA Username */
84
  protected String tsaUsername;
85
  /** TSA password */
86
  protected String tsaPassword;
87
  /** Estimate of the received time stamp token */
88
  protected int tokSzEstimate;
89
90
  /**
91
   * Creates an instance of a TSAClient that will use BouncyCastle.
92
   * 
93
   * @param url
94
   *          String - Time Stamp Authority URL (i.e.
95
   *          "http://tsatest1.digistamp.com/TSA")
96
   */
97
  public TSAClientBouncyCastle(String url) {
98
    this(url, null, null, 4096);
99
  }
100
101
  /**
102
   * Creates an instance of a TSAClient that will use BouncyCastle.
103
   * 
104
   * @param url
105
   *          String - Time Stamp Authority URL (i.e.
106
   *          "http://tsatest1.digistamp.com/TSA")
107
   * @param username
108
   *          String - user(account) name
109
   * @param password
110
   *          String - password
111
   */
112
  public TSAClientBouncyCastle(String url, String username, String password) {
113
    this(url, username, password, 4096);
114
  }
115
116
  /**
117
   * Constructor. Note the token size estimate is updated by each call, as the
118
   * token size is not likely to change (as long as we call the same TSA using
119
   * the same imprint length).
120
   * 
121
   * @param url
122
   *          String - Time Stamp Authority URL (i.e.
123
   *          "http://tsatest1.digistamp.com/TSA")
124
   * @param username
125
   *          String - user(account) name
126
   * @param password
127
   *          String - password
128
   * @param tokSzEstimate
129
   *          int - estimated size of received time stamp token (DER encoded)
130
   */
131
  public TSAClientBouncyCastle(String url, String username, String password,
132
      int tokSzEstimate) {
133
    this.tsaURL = url;
134
    this.tsaUsername = username;
135
    this.tsaPassword = password;
136
    this.tokSzEstimate = tokSzEstimate;
137
  }
138
139
  /**
140
   * Get the token size estimate. Returned value reflects the result of the last
141
   * succesfull call, padded
142
   * 
143
   * @return an estimate of the token size
144
   */
145
  @Override
146
  public int getTokenSizeEstimate() {
147
    return tokSzEstimate;
148
  }
149
150
  /**
151
   * Get RFC 3161 timeStampToken. Method may return null indicating that
152
   * timestamp should be skipped.
153
   * 
154
   * @param caller
155
   *          PdfPKCS7 - calling PdfPKCS7 instance (in case caller needs it)
156
   * @param imprint
157
   *          byte[] - data imprint to be time-stamped
158
   * @return byte[] - encoded, TSA signed data of the timeStampToken
159
   * @throws Exception
160
   *           - TSA request failed
161
   * @see com.lowagie.text.pdf.TSAClient#getTimeStampToken(com.lowagie.text.pdf.PdfPKCS7,
162
   *      byte[])
163
   */
164
  @Override
165
  public byte[] getTimeStampToken(PdfPKCS7 caller, byte[] imprint)
166
      throws Exception {
167
    return getTimeStampToken(imprint);
168
  }
169
170
  /**
171
   * Get timestamp token - Bouncy Castle request encoding / decoding layer
172
   */
173
  protected byte[] getTimeStampToken(byte[] imprint) throws Exception {
174
    byte[] respBytes = null;
175
    try {
176
      // Setup the time stamp request
177
      TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator();
178
      tsqGenerator.setCertReq(true);
179
      // tsqGenerator.setReqPolicy("1.3.6.1.4.1.601.10.3.1");
180
      BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis());
181
      TimeStampRequest request = tsqGenerator.generate(
182
          X509ObjectIdentifiers.id_SHA1.getId(), imprint, nonce);
183
      byte[] requestBytes = request.getEncoded();
184
185
      // Call the communications layer
186
      respBytes = getTSAResponse(requestBytes);
187
188
      // Handle the TSA response
189
      TimeStampResponse response = new TimeStampResponse(respBytes);
190
191
      // validate communication level attributes (RFC 3161 PKIStatus)
192
      response.validate(request);
193
      PKIFailureInfo failure = response.getFailInfo();
194
      int value = (failure == null) ? 0 : failure.intValue();
195 1 1. getTimeStampToken : negated conditional → NO_COVERAGE
      if (value != 0) {
196
        // @todo: Translate value of 15 error codes defined by
197
        // PKIFailureInfo to string
198
        throw new Exception(MessageLocalization.getComposedMessage(
199
            "invalid.tsa.1.response.code.2", tsaURL, String.valueOf(value)));
200
      }
201
      // @todo: validate the time stap certificate chain (if we want
202
      // assure we do not sign using an invalid timestamp).
203
204
      // extract just the time stamp token (removes communication status
205
      // info)
206
      TimeStampToken tsToken = response.getTimeStampToken();
207 1 1. getTimeStampToken : negated conditional → NO_COVERAGE
      if (tsToken == null) {
208
        throw new Exception(MessageLocalization.getComposedMessage(
209
            "tsa.1.failed.to.return.time.stamp.token.2", tsaURL,
210
            response.getStatusString()));
211
      }
212
      TimeStampTokenInfo info = tsToken.getTimeStampInfo(); // to view
213
                                                            // details
214
      byte[] encoded = tsToken.getEncoded();
215
      long stop = System.currentTimeMillis();
216
217
      // Update our token size estimate for the next call (padded to be
218
      // safe)
219 1 1. getTimeStampToken : Replaced integer addition with subtraction → NO_COVERAGE
      this.tokSzEstimate = encoded.length + 32;
220 1 1. getTimeStampToken : mutated return of Object value for com/lowagie/text/pdf/TSAClientBouncyCastle::getTimeStampToken to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
      return encoded;
221
    } catch (Exception e) {
222
      throw e;
223
    } catch (Throwable t) {
224
      throw new Exception(MessageLocalization.getComposedMessage(
225
          "failed.to.get.tsa.response.from.1", tsaURL), t);
226
    }
227
  }
228
229
  /**
230
   * Get timestamp token - communications layer
231
   * 
232
   * @return - byte[] - TSA response, raw bytes (RFC 3161 encoded)
233
   */
234
  protected byte[] getTSAResponse(byte[] requestBytes) throws Exception {
235
    // Setup the TSA connection
236
    URL url = new URL(tsaURL);
237
    URLConnection tsaConnection;
238
    tsaConnection = url.openConnection();
239
240 1 1. getTSAResponse : removed call to java/net/URLConnection::setDoInput → NO_COVERAGE
    tsaConnection.setDoInput(true);
241 1 1. getTSAResponse : removed call to java/net/URLConnection::setDoOutput → NO_COVERAGE
    tsaConnection.setDoOutput(true);
242 1 1. getTSAResponse : removed call to java/net/URLConnection::setUseCaches → NO_COVERAGE
    tsaConnection.setUseCaches(false);
243 1 1. getTSAResponse : removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE
    tsaConnection.setRequestProperty("Content-Type",
244
        "application/timestamp-query");
245
    // tsaConnection.setRequestProperty("Content-Transfer-Encoding",
246
    // "base64");
247 1 1. getTSAResponse : removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE
    tsaConnection.setRequestProperty("Content-Transfer-Encoding", "binary");
248
249 2 1. getTSAResponse : negated conditional → NO_COVERAGE
2. getTSAResponse : negated conditional → NO_COVERAGE
    if ((tsaUsername != null) && !tsaUsername.equals("")) {
250
      String userPassword = tsaUsername + ":" + tsaPassword;
251 1 1. getTSAResponse : removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE
      tsaConnection.setRequestProperty("Authorization", "Basic "
252
          + new String(Base64.getEncoder().encode(userPassword.getBytes())));
253
    }
254
    OutputStream out = tsaConnection.getOutputStream();
255 1 1. getTSAResponse : removed call to java/io/OutputStream::write → NO_COVERAGE
    out.write(requestBytes);
256 1 1. getTSAResponse : removed call to java/io/OutputStream::close → NO_COVERAGE
    out.close();
257
258
    // Get TSA response as a byte array
259
    InputStream inp = tsaConnection.getInputStream();
260
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
261
    byte[] buffer = new byte[1024];
262
    int bytesRead = 0;
263 2 1. getTSAResponse : changed conditional boundary → NO_COVERAGE
2. getTSAResponse : negated conditional → NO_COVERAGE
    while ((bytesRead = inp.read(buffer, 0, buffer.length)) >= 0) {
264 1 1. getTSAResponse : removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE
      baos.write(buffer, 0, bytesRead);
265
    }
266
    byte[] respBytes = baos.toByteArray();
267
268
    String encoding = tsaConnection.getContentEncoding();
269 2 1. getTSAResponse : negated conditional → NO_COVERAGE
2. getTSAResponse : negated conditional → NO_COVERAGE
    if (encoding != null && encoding.equalsIgnoreCase("base64")) {
270
      respBytes = Base64.getDecoder().decode(respBytes);
271
    }
272 1 1. getTSAResponse : mutated return of Object value for com/lowagie/text/pdf/TSAClientBouncyCastle::getTSAResponse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE
    return respBytes;
273
  }
274
}

Mutations

195

1.1
Location : getTimeStampToken
Killed by : none
negated conditional → NO_COVERAGE

207

1.1
Location : getTimeStampToken
Killed by : none
negated conditional → NO_COVERAGE

219

1.1
Location : getTimeStampToken
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

220

1.1
Location : getTimeStampToken
Killed by : none
mutated return of Object value for com/lowagie/text/pdf/TSAClientBouncyCastle::getTimeStampToken to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

240

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setDoInput → NO_COVERAGE

241

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setDoOutput → NO_COVERAGE

242

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setUseCaches → NO_COVERAGE

243

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE

247

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE

249

1.1
Location : getTSAResponse
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : getTSAResponse
Killed by : none
negated conditional → NO_COVERAGE

251

1.1
Location : getTSAResponse
Killed by : none
removed call to java/net/URLConnection::setRequestProperty → NO_COVERAGE

255

1.1
Location : getTSAResponse
Killed by : none
removed call to java/io/OutputStream::write → NO_COVERAGE

256

1.1
Location : getTSAResponse
Killed by : none
removed call to java/io/OutputStream::close → NO_COVERAGE

263

1.1
Location : getTSAResponse
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getTSAResponse
Killed by : none
negated conditional → NO_COVERAGE

264

1.1
Location : getTSAResponse
Killed by : none
removed call to java/io/ByteArrayOutputStream::write → NO_COVERAGE

269

1.1
Location : getTSAResponse
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : getTSAResponse
Killed by : none
negated conditional → NO_COVERAGE

272

1.1
Location : getTSAResponse
Killed by : none
mutated return of Object value for com/lowagie/text/pdf/TSAClientBouncyCastle::getTSAResponse to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.4.2