Implementation of RFC3161 in Groovy script

I need to get timestamp from a TSA in a Groovy script. I try to use following script to get timestamp.

import org.bouncycastle.asn1.*
import org.bouncycastle.asn1.cmp.*
import org.bouncycastle.operator.*
import org.bouncycastle.tsp.*
import com.google.inject.AbstractModule
import com.google.inject.Provides
import com.google.inject.Inject

public interface TSAClient {
  public byte[] getToken(byte[] imprint)
}

class TSAModule extends AbstractModule {
  private String url
  private String username
  private String password

  public TSAModule(String url, String username, String password) {
    this.url = url
    this.username = username
    this.password = password
  }

  @Override
  protected void configure() {
  }

  @Provides
  TSAClient tsaClient() {
    new TSAClientImpl(url, username, password)
  }
}

public class TSAClientImpl implements TSAClient {
  String tsaURL = "http://localhost:5050/timestamp"
  String tsaUsername
  String tsaPassword

  public TSAClientImpl() {
  }

  public TSAClientImpl(String url, String username, String password) {
    this.tsaURL = url
    this.tsaUsername = username
    this.tsaPassword = password
  }

  @Override
  public byte[] getToken(byte[] imprint) {
    byte[] respBytes = null

    def algoFinder = new DefaultDigestAlgorithmIdentifierFinder()
    def algoIdentifier = algoFinder.find("SHA-256")

    // Setup the time stamp request
    def tsqGenerator = new TimeStampRequestGenerator()
    tsqGenerator.certReq = true
    //tsqGenerator.reqPolicy = new ASN1ObjectIdentifier("1.3.6.1.4.1.13762.3")
    def nonce = BigInteger.valueOf(System.currentTimeMillis())
    def request = tsqGenerator.generate(algoIdentifier.objectId, imprint, nonce)
    byte[] requestBytes = request.encoded

    // Call the communications layer
    respBytes = getTSAResponse(requestBytes)

    // Handle the TSA response
    def response = new TimeStampResponse(respBytes)

    // validate communication level attributes (RFC 3161 PKIStatus)
    response.validate(request)

    def failure = response.failInfo
    int value = (failure == null) ? 0 : failure.intValue()
    if (value != 0) {
      throw new IOException("TSA failure: ${value} (${response.statusString})")
    }

    // extract just the time stamp token (removes communication status info)
    def tsToken = response.timeStampToken
    if (tsToken == null) {
      throw new IOException("TSA failed to return token: ${response.status} (${response.statusString})")
    }
    def tsTokenInfo = tsToken.timeStampInfo
    byte[] encoded = tsToken.encoded

    encoded
  }

  def getTSAResponse(byte[] requestBytes) {
    // Setup the TSA connection
    def tsaConnection = new URL(tsaURL).openConnection()
    tsaConnection.doInput = true
    tsaConnection.doOutput = true
    tsaConnection.useCaches = false

    tsaConnection.setRequestProperty("Content-Type", "application/timestamp-query")
    //tsaConnection.setRequestProperty("Content-Transfer-Encoding", "base64")
    tsaConnection.setRequestProperty("Content-Transfer-Encoding", "binary")

    if (tsaUsername != null && tsaUsername != "") {
      String userPassword = tsaUsername + ":" + tsaPassword
      tsaConnection.setRequestProperty("Authorization", "Basic " +
          userPassword.bytes.encodeBase64().toString())
    }
    def out = tsaConnection.outputStream
    out << requestBytes
    out.close()

    // Get TSA response as a byte array
    def inp = tsaConnection.inputStream
    def baos = new ByteArrayOutputStream()
    baos << inp
    byte[] respBytes = baos.toByteArray()

    def encoding = tsaConnection.getContentEncoding()

    if (encoding != null && encoding.equalsIgnoreCase("base64")) {
      respBytes = new String(respBytes).decodeBase64()
    }

    respBytes
  }
}

I imported bcprov-jdk15on-1.62.jar, bcpkix-jdk15on-1.62.jar, guice-4.2.2.jar and javax.inject-1.jar dependencies. I get following error message during execution:

java.lang.NoClassDefFoundError: Unable to load class com.google.inject.AbstractModule due to missing dependency [Lorg/aopalliance/intercept/MethodInterceptor;

Source of code: seginf/Sinapuli-service/src/main/groovy/garantito/sinapuli/tsa at master · carohadad/seginf · GitHub

Is there any simpler solution in Katalon Studio for this purpose?

Hi plaidshirtakos,

You need to import aopalliance jar file.

Thanks

@duyluong : I added it, but got following error message:
groovy.lang.GroovyRuntimeException: Failed to create Script instance for class: interface TSAClient. Reason: java.lang.InstantiationException: TSAClient

Please split these class to single files:

TSAClient 
TSAModule
TSAClientImpl 

I splitted it into 3 files. I got error message, when I try to add it to testcase.

Hi @plaidshirtakos,

Custom Keywords are the list of method with annotation @Keyword. In your case, you don’t need to use Custom Keywords here. Just declare an instance of: TSAClientImpl then use like Java normally.

Thanks

Hello @duyluong,

I tried with this code, but unable to use this. I use Base64 encoded format of a 89 kB PDF file.
timestamp.TSAClientImpl tsaimpl = new timestamp.TSAClientImpl();

tsaimpl.getToken("");

I got following error message:
-1: String too long. The given string is 121216 Unicode code units long, but only a maximum of 65535 is allowed.