예제 #1
0
  /**
   * Checks if the {@code TimeStampToken} matches the signed data.
   *
   * @param data the array of {@code byte} representing the timestamped data
   * @return true if the data is verified by the TimeStampToken
   */
  public boolean matchData(final byte[] data) {

    try {

      messageImprintData = data != null;
      final TimeStampTokenInfo timeStampInfo = timeStamp.getTimeStampInfo();
      final ASN1ObjectIdentifier hashAlgorithm = timeStampInfo.getHashAlgorithm().getAlgorithm();
      final DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(hashAlgorithm.getId());

      final byte[] computedDigest = DSSUtils.digest(digestAlgorithm, data);
      final byte[] timestampDigest = timeStampInfo.getMessageImprintDigest();
      messageImprintIntact = Arrays.equals(computedDigest, timestampDigest);
      if (!messageImprintIntact) {
        logger.error(
            "Computed digest ({}) on the extracted data from the document : {}",
            digestAlgorithm,
            Hex.encodeHexString(computedDigest));
        logger.error("Digest present in TimestampToken: {}", Hex.encodeHexString(timestampDigest));
        logger.error(
            "Digest in TimestampToken matches digest of extracted data from document: {}",
            messageImprintIntact);
      }
    } catch (DSSException e) {

      messageImprintIntact = false;
      signedDataMessage = "Timestamp digest problem: " + e.getMessage();
    }
    return messageImprintIntact;
  }
예제 #2
0
  @Override
  public boolean isSignedBy(final CertificateToken issuerToken) {

    if (this.issuerToken != null) {

      return this.issuerToken.equals(issuerToken);
    }
    final TimestampValidation timestampValidation = validateTimestampToken(timeStamp, issuerToken);
    final TimestampValidity timestampValidity = timestampValidation.getValidity();
    signatureInvalidityReason = timestampValidity.name();
    signatureValid = timestampValidation.isValid();
    if (signatureValid) {

      this.issuerToken = issuerToken;

      issuerX500Principal = issuerToken.getSubjectX500Principal();
      final String algorithm = issuerToken.getPublicKey().getAlgorithm();
      final EncryptionAlgorithm encryptionAlgorithm = EncryptionAlgorithm.forName(algorithm);
      final AlgorithmIdentifier hashAlgorithm = timeStamp.getTimeStampInfo().getHashAlgorithm();
      final DigestAlgorithm digestAlgorithm =
          DigestAlgorithm.forOID(hashAlgorithm.getAlgorithm().getId());
      signatureAlgorithm = SignatureAlgorithm.getAlgorithm(encryptionAlgorithm, digestAlgorithm);
    }
    return signatureValid;
  }
예제 #3
0
  @Override
  public String toString(String indentStr) {

    try {

      final StringBuffer out = new StringBuffer();
      out.append(indentStr)
          .append("TimestampToken[signedBy=")
          .append(issuerToken == null ? "?" : issuerToken.getDSSIdAsString());
      out.append(", generated: ")
          .append(DSSUtils.formatInternal(timeStamp.getTimeStampInfo().getGenTime()));
      out.append(" / ").append(timeStampType).append('\n');
      if (signatureValid) {

        indentStr += "\t";
        out.append(indentStr).append("Timestamp's signature validity: VALID").append('\n');
        indentStr = indentStr.substring(1);
      } else {

        if (!signatureInvalidityReason.isEmpty()) {

          indentStr += "\t";
          out.append(indentStr)
              .append("Timestamp's signature validity: INVALID")
              .append(" - ")
              .append(signatureInvalidityReason)
              .append('\n');
          indentStr = indentStr.substring(1);
        }
      }
      indentStr += "\t";
      if (messageImprintIntact != null) {

        if (messageImprintIntact) {

          out.append(indentStr).append("Timestamp MATCHES the signed data.").append('\n');
        } else {

          out.append(indentStr).append("Timestamp DOES NOT MATCH the signed data.").append('\n');
          if (!signedDataMessage.isEmpty()) {

            out.append(indentStr).append("- ").append(signedDataMessage).append('\n');
          }
        }
      }
      indentStr = indentStr.substring(1);
      if (issuerToken != null) {

        indentStr += "\t";
        out.append(issuerToken.toString(indentStr)).append('\n');
        indentStr = indentStr.substring(1);
        out.append(indentStr);
      }
      out.append("]");
      return out.toString();
    } catch (Exception e) {
      return getClass().getName();
    }
  }
예제 #4
0
 @Override
 public byte[] getEncoded() {
   try {
     return timeStamp.getEncoded();
   } catch (IOException e) {
     throw new DSSException(e);
   }
 }
예제 #5
0
 @Override
 public String getAbbreviation() {
   return timeStampType.name()
       + ": "
       + getDSSId()
       + ": "
       + DSSUtils.formatInternal(timeStamp.getTimeStampInfo().getGenTime());
 }
예제 #6
0
  /**
   * Returns an ASN.1 encoded bytes representing the {@code TimeStampToken}
   *
   * @param timeStampToken {@code TimeStampToken}
   * @return Returns an ASN.1 encoded bytes representing the {@code TimeStampToken}
   */
  public static byte[] getEncoded(final TimeStampToken timeStampToken) throws DSSException {

    try {
      final byte[] encoded = timeStampToken.getEncoded();
      return encoded;
    } catch (IOException e) {
      throw new DSSException(e);
    }
  }
예제 #7
0
  private TimestampValidation validateTimestampToken(
      final TimeStampToken timeStampToken, final CertificateToken issuerToken) {

    TimestampValidity timestampValidity;
    try {

      final JcaSimpleSignerInfoVerifierBuilder verifierBuilder =
          new JcaSimpleSignerInfoVerifierBuilder();
      final X509Certificate x509Certificate = issuerToken.getCertificate();
      final SignerInformationVerifier verifier = verifierBuilder.build(x509Certificate);
      timeStampToken.validate(verifier);
      timestampValidity = TimestampValidity.VALID;
    } catch (IllegalArgumentException e) {
      if (logger.isDebugEnabled()) {
        logger.debug("No signing certificate for timestamp token: ", e);
      } else {
        logger.info("No signing certificate for timestamp token: ", e.getMessage());
      }
      timestampValidity = TimestampValidity.NO_SIGNING_CERTIFICATE;
    } catch (TSPValidationException e) {
      if (logger.isDebugEnabled()) {
        logger.debug("No valid signature for timestamp token: ", e);
      } else {
        logger.info("No valid signature for timestamp token: " + e.getMessage());
      }
      timestampValidity = TimestampValidity.NOT_VALID_SIGNATURE;
    } catch (TSPException e) {
      if (logger.isDebugEnabled()) {
        logger.debug("No valid structure for timestamp token: ", e);
      } else {
        logger.info("No valid structure for timestamp token: " + e.getMessage());
      }
      timestampValidity = TimestampValidity.NOT_VALID_STRUCTURE;
    } catch (OperatorCreationException e) {
      if (logger.isDebugEnabled()) {
        logger.debug("No valid structure for timestamp token: ", e);
      } else {
        logger.info("No valid structure for timestamp token: " + e.getMessage());
      }
      timestampValidity = TimestampValidity.NOT_VALID_STRUCTURE;
    }
    final TimestampValidation timestampValidation = new TimestampValidation(timestampValidity);
    return timestampValidation;
  }
예제 #8
0
  /**
   * Constructor with an indication of the timestamp type. The default constructor for {@code
   * TimestampToken}.
   *
   * @param timeStamp {@code TimeStampToken}
   * @param type {@code TimestampType}
   * @param certPool {@code CertificatePool} which is used to identify the signing certificate of
   *     the timestamp
   */
  public TimestampToken(
      final TimeStampToken timeStamp, final TimestampType type, final CertificatePool certPool) {

    this.timeStamp = timeStamp;
    this.timeStampType = type;
    this.extraInfo = new TokenValidationExtraInfo();
    wrappedSource = new CAdESCertificateSource(timeStamp, certPool);
    final Collection<CertificateToken> certs = wrappedSource.getCertificates();
    for (final CertificateToken certificateToken : certs) {

      final byte[] encoded = certificateToken.getEncoded();
      final Certificate certificate = Certificate.getInstance(encoded);
      final X509CertificateHolder x509CertificateHolder = new X509CertificateHolder(certificate);
      if (timeStamp.getSID().match(x509CertificateHolder)) {

        boolean valid = isSignedBy(certificateToken);
        if (valid) {
          break;
        }
      }
    }
  }
예제 #9
0
  public byte[] getTimeStampToken(byte[] digest)
      throws NoSuchAlgorithmException, UnsupportedEncodingException, TSPException {

    TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator();
    tsqGenerator.setCertReq(true);
    if (tsaOid != null) tsqGenerator.setReqPolicy(tsaOid);
    TimeStampRequest tsReq =
        tsqGenerator.generate(TSPAlgorithms.SHA1, digest, BigInteger.valueOf(100));
    byte[] respBytes;
    try {
      byte[] requestBytes = tsReq.getEncoded();
      URL url = new URL(tsaURL);
      HttpsURLConnection tsaConnection = (HttpsURLConnection) url.openConnection();
      String user_pass = Base64.encodeToString((tsaUsername + ":" + tsaPassword).getBytes(), 0);
      tsaConnection.setRequestProperty("Authorization", "Basic " + user_pass);
      tsaConnection.setDoInput(true);
      tsaConnection.setDoOutput(true);
      tsaConnection.setUseCaches(false);
      tsaConnection.setRequestProperty("Content-Type", "application/timestamp-query");
      tsaConnection.setRequestProperty("Content-Transfer-Encoding", "binary");
      OutputStream out = tsaConnection.getOutputStream();
      out.write(requestBytes);
      out.close();
      InputStream inp = tsaConnection.getInputStream();
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      byte[] buffer = new byte[1024];
      int bytesRead = 0;
      while ((bytesRead = inp.read(buffer, 0, buffer.length)) >= 0) {
        baos.write(buffer, 0, bytesRead);
      }
      respBytes = baos.toByteArray();
      String encoding = tsaConnection.getContentEncoding();
      if (encoding != null && encoding.equalsIgnoreCase("base64")) {
        respBytes = Base64.decode(new String(respBytes), 0);
      }

      if (respBytes == null) {
        String error = "Error: Impossible to get TSA response";
        Log.e(TAG, error);
      }
      TimeStampResponse tsRes = new TimeStampResponse(respBytes);

      tsRes.validate(tsReq);
      PKIFailureInfo failure = tsRes.getFailInfo();
      int value = (failure == null) ? 0 : failure.intValue();
      if (value != 0) {
        String error = "Error: Invalid TSA response (" + tsRes.getStatusString() + ")";
        Log.e(TAG, error);
        return null;
      }
      TimeStampToken myTSToken = tsRes.getTimeStampToken();
      if (myTSToken == null) {
        String error = "Error: Invalid TSA response (NULL)";
        Log.e(TAG, error);
        return null;
      }
      return myTSToken.getEncoded();
    } catch (IOException | TSPException e) {
      Log.e(TAG, e.getMessage());
    }
    return null;
  }
예제 #10
0
  public byte[] timeStamp(byte[] data, RevocationData revocationData) throws Exception {
    // digest the message
    MessageDigest messageDigest = MessageDigest.getInstance(this.digestAlgo);
    byte[] digest = messageDigest.digest(data);

    // generate the TSP request
    BigInteger nonce = new BigInteger(128, new SecureRandom());
    TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator();
    requestGenerator.setCertReq(true);
    if (null != this.requestPolicy) {
      requestGenerator.setReqPolicy(this.requestPolicy);
    }
    TimeStampRequest request = requestGenerator.generate(this.digestAlgoOid, digest, nonce);
    byte[] encodedRequest = request.getEncoded();

    // create the HTTP client
    HttpClient httpClient = new HttpClient();
    if (null != this.username) {
      Credentials credentials = new UsernamePasswordCredentials(this.username, this.password);
      httpClient.getState().setCredentials(AuthScope.ANY, credentials);
    }
    if (null != this.proxyHost) {
      httpClient.getHostConfiguration().setProxy(this.proxyHost, this.proxyPort);
    }

    // create the HTTP POST request
    PostMethod postMethod = new PostMethod(this.tspServiceUrl);
    RequestEntity requestEntity =
        new ByteArrayRequestEntity(encodedRequest, "application/timestamp-query");
    postMethod.addRequestHeader("User-Agent", this.userAgent);
    postMethod.setRequestEntity(requestEntity);

    // invoke TSP service
    int statusCode = httpClient.executeMethod(postMethod);
    if (HttpStatus.SC_OK != statusCode) {
      LOG.error("Error contacting TSP server " + this.tspServiceUrl);
      throw new Exception("Error contacting TSP server " + this.tspServiceUrl);
    }

    // HTTP input validation
    Header responseContentTypeHeader = postMethod.getResponseHeader("Content-Type");
    if (null == responseContentTypeHeader) {
      throw new RuntimeException("missing Content-Type header");
    }
    String contentType = responseContentTypeHeader.getValue();
    if (!contentType.startsWith("application/timestamp-reply")) {
      LOG.debug("response content: " + postMethod.getResponseBodyAsString());
      throw new RuntimeException("invalid Content-Type: " + contentType);
    }
    if (0 == postMethod.getResponseContentLength()) {
      throw new RuntimeException("Content-Length is zero");
    }

    // TSP response parsing and validation
    InputStream inputStream = postMethod.getResponseBodyAsStream();
    TimeStampResponse timeStampResponse = new TimeStampResponse(inputStream);
    timeStampResponse.validate(request);

    if (0 != timeStampResponse.getStatus()) {
      LOG.debug("status: " + timeStampResponse.getStatus());
      LOG.debug("status string: " + timeStampResponse.getStatusString());
      PKIFailureInfo failInfo = timeStampResponse.getFailInfo();
      if (null != failInfo) {
        LOG.debug("fail info int value: " + failInfo.intValue());
        if (PKIFailureInfo.unacceptedPolicy == failInfo.intValue()) {
          LOG.debug("unaccepted policy");
        }
      }
      throw new RuntimeException(
          "timestamp response status != 0: " + timeStampResponse.getStatus());
    }
    TimeStampToken timeStampToken = timeStampResponse.getTimeStampToken();
    SignerId signerId = timeStampToken.getSID();
    BigInteger signerCertSerialNumber = signerId.getSerialNumber();
    X500Principal signerCertIssuer = signerId.getIssuer();
    LOG.debug("signer cert serial number: " + signerCertSerialNumber);
    LOG.debug("signer cert issuer: " + signerCertIssuer);

    // TSP signer certificates retrieval
    CertStore certStore =
        timeStampToken.getCertificatesAndCRLs("Collection", BouncyCastleProvider.PROVIDER_NAME);
    Collection<? extends Certificate> certificates = certStore.getCertificates(null);
    X509Certificate signerCert = null;
    Map<String, X509Certificate> certificateMap = new HashMap<String, X509Certificate>();
    for (Certificate certificate : certificates) {
      X509Certificate x509Certificate = (X509Certificate) certificate;
      if (signerCertIssuer.equals(x509Certificate.getIssuerX500Principal())
          && signerCertSerialNumber.equals(x509Certificate.getSerialNumber())) {
        signerCert = x509Certificate;
      }
      String ski = Hex.encodeHexString(getSubjectKeyId(x509Certificate));
      certificateMap.put(ski, x509Certificate);
      LOG.debug(
          "embedded certificate: " + x509Certificate.getSubjectX500Principal() + "; SKI=" + ski);
    }

    // TSP signer cert path building
    if (null == signerCert) {
      throw new RuntimeException("TSP response token has no signer certificate");
    }
    List<X509Certificate> tspCertificateChain = new LinkedList<X509Certificate>();
    X509Certificate certificate = signerCert;
    do {
      LOG.debug("adding to certificate chain: " + certificate.getSubjectX500Principal());
      tspCertificateChain.add(certificate);
      if (certificate.getSubjectX500Principal().equals(certificate.getIssuerX500Principal())) {
        break;
      }
      String aki = Hex.encodeHexString(getAuthorityKeyId(certificate));
      certificate = certificateMap.get(aki);
    } while (null != certificate);

    // verify TSP signer signature
    timeStampToken.validate(tspCertificateChain.get(0), BouncyCastleProvider.PROVIDER_NAME);

    // verify TSP signer certificate
    this.validator.validate(tspCertificateChain, revocationData);

    LOG.debug("time-stamp token time: " + timeStampToken.getTimeStampInfo().getGenTime());

    byte[] timestamp = timeStampToken.getEncoded();
    return timestamp;
  }
예제 #11
0
 public AttributeTable getUnsignedAttributes() {
   return timeStamp.getUnsignedAttributes();
 }
예제 #12
0
  /**
   * Retrieves the encoded signed data digest value.
   *
   * @return base 64 encoded {@code String}
   */
  public String getEncodedSignedDataDigestValue() {

    final byte[] messageImprintDigest = timeStamp.getTimeStampInfo().getMessageImprintDigest();
    return Base64.encodeBase64String(messageImprintDigest);
  }
예제 #13
0
  /**
   * Retrieves the {@code DigestAlgorithm} used to generate the digest value to timestamp.
   *
   * @return {@code DigestAlgorithm}
   */
  public DigestAlgorithm getSignedDataDigestAlgo() {

    final ASN1ObjectIdentifier oid = timeStamp.getTimeStampInfo().getHashAlgorithm().getAlgorithm();
    return DigestAlgorithm.forOID(oid.getId());
  }
예제 #14
0
  /**
   * Retrieves the timestamp generation time.
   *
   * @return {@code Date}
   */
  public Date getGenerationTime() {

    return timeStamp.getTimeStampInfo().getGenTime();
  }