module PkernelJce::Rfc3161::Response

Public Instance Methods

dump(resp, opts = { }) click to toggle source

end parse()

# File lib/pkernel_jce/rfc3161.rb, line 266
def dump(resp, opts = { })
  if resp.nil?
    raise PkernelJce::Error, "RFC3161 response to dump is nil."
  end

  resp.encode        
end
generate(opts = { }) click to toggle source

generate rfc3161 timestamp token

# File lib/pkernel_jce/rfc3161.rb, line 18
def generate(opts = { })
  bin = opts[:bin]
  file = opts[:file]

  if not (file.nil? or file.empty?)
    breq = IoUtils.file_to_memory_byte_array(file)
  elsif not bin.nil?
    breq = IoUtils.ensure_java_bytes(bin)
  else
    raise PkernelJce::Error, "No request file or memory is given to generate timestamp response"
  end


  id = opts[:identity]
  if id.nil?
    raise PkernelJce::Error, "Identity is not given to generate timestamping token"
  end

  req = org.bouncycastle.tsp.TimeStampRequest.new(breq) 
  #p req.messageImprintAlgOID

  begin
    dgstEng = BcHelpers.find_digest_calculator(req.messageImprintAlgOID)
    PkernelJce::GConf.instance.glog.debug "Timestamp request using hash '#{dgstEng}'"
  rescue PkernelJce::Error => ex
    opts[:status] = Pkernel::Rfc3161::RESP_REJECTION
    opts[:reason] = Pkernel::Rfc3161::REASON_BAD_ALG
    opts[:reasonMsg] = "Digest not supported"
  end

  chain = id.chain
  list = java.util.ArrayList.new
  chain.each do |c|
    list.add(c) 
  end
  store = org.bouncycastle.cert.jcajce.JcaCertStore.new(list)

  # this one seems useless since the actual algo shall be taken from request anyway...
  signHashAlgo = opts[:signHash] || "SHA256"
  policyId = opts[:policy_id] || "1.2.3.4.1"
  signInfo = org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder.new.setProvider(id.provider).build(PkernelJce::KeyPair.derive_signing_algo(id.privKey,signHashAlgo), id.privKey, id.certificate)

  # policy 1.2.3.4.1 = tsa_policy1
  gen = org.bouncycastle.tsp.TimeStampTokenGenerator.new(signInfo, BcHelpers.find_digest_calculator(signHashAlgo), org.bouncycastle.asn1.ASN1ObjectIdentifier.new(policyId))
  # policy 1.2 = ISO Member body
  #gen = org.bouncycastle.tsp.TimeStampTokenGenerator.new(signInfo, SHA256DigestCalculator.new, org.bouncycastle.asn1.ASN1ObjectIdentifier.new("1.2"))

  gen.addCertificates(store)

  if req.cert_req?
    PkernelJce::GConf.instance.glog.debug "Client requested to include certificate for timestamping"
    # this option requires the request to reqCert set first if not error shall be thrown at the verification end
    gen.setTSA(org.bouncycastle.asn1.x509.GeneralName.new(PkernelJce::Certificate.ensure_bc_cert(id.certificate).subject_to_x500))
  end

  status = opts[:status] || Pkernel::Rfc3161::RESP_GRANTED
  reason = opts[:reason] || Pkernel::Rfc3161::REASON_SYS_FAILURE
  reasonMsg = opts[:reasonMsg] || ""
  
  respGen = org.bouncycastle.tsp.TimeStampResponseGenerator.new(gen, org.bouncycastle.tsp.TSPAlgorithms::ALLOWED)
  
  if status == Pkernel::Rfc3161::RESP_GRANTED or status == Pkernel::Rfc3161::RESP_GRANTED_WITH_MODS
    
    # etsi want min 1 sec...:)
    accuracy = opts[:accuracy] || { seconds: 1 }
    if not accuracy[:seconds].nil?
      PkernelJce::GConf.instance.glog.debug "Timestamping setting accuracy #{accuracy[:seconds]} seconds"
      gen.setAccuracySeconds(accuracy[:seconds].to_i)
    end

    if not accuracy[:milis].nil?
      PkernelJce::GConf.instance.glog.debug "Timestamping setting accuracy #{accuracy[:milis]} mili seconds"
      gen.setAccuracyMillis(accuracy[:milis].to_i)
    end

    if not accuracy[:micros].nil?
      PkernelJce::GConf.instance.glog.debug "Timestamping setting accuracy #{accuracy[:micros]} micro seconds"
      gen.setAccuracyMicros(accuracy[:micros].to_i)
    end

    tsResp = respGen.generateGrantedResponse(req, java.math.BigInteger.new(SecureRandom.uuid.gsub("-",""),16), java.util.Date.new)
    
  else
    
    tsResp = respGen.generateFailResponse(status, reason, reasonMsg)
  end
  #resp = org.bouncycastle.tsp.TimeStampResponse.new(tsResp.getEncoded())

  #resp
  tsResp 
end
parse(opts = {}) click to toggle source

end generate()

# File lib/pkernel_jce/rfc3161.rb, line 113
def parse(opts = {})

  file = opts[:file]
  bin = opts[:bin]

  if not (file.nil? or file.empty?)
    bresp = IoUtils.file_to_memory_byte_array(file)
  elsif not bin.nil?
    bresp = IoUtils.ensure_java_bytes(bin)
  else
    raise PkernelJce::Error, "No file or memory is given to parse timestamp response"
  end

  result = { }
  verifyResp = opts[:verifyResp] || true
  
  resp = org.bouncycastle.tsp.TimeStampResponse.new(bresp)

  result[:status] = resp.status

  if resp.status == Pkernel::Rfc3161::RESP_GRANTED || resp.status == Pkernel::Rfc3161::RESP_GRANTED_WITH_MODS

    token = resp.getTimeStampToken

    if not token.nil?
      info = token.getTimeStampInfo
    else
      PkernelJce::GConf.instance.glog.warn "Timestamp does not contain token!"
    end



    if not token.nil? and verifyResp

      tsaCert = opts[:tsaCert]

      signingCert = nil 
      token.getCertificates.to_a.each do |c|
        if c.subject_to_x500.equals(info.getTsa.name)
          signingCert = c
          break
        end
      end

      if not tsaCert.nil?
        # check if tsaCert and signingCert is same
        if not tsaCert.equals(signingCert)
          raise PkernelJce::Error, "Given TSA cert and signing cert obtained from the timestamp token is not the same"
        end
      end

      prov = PkernelJce::Provider.add_default
      begin
        token.validate(org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder.new.setProvider(prov).build(signingCert))
        result[:signature_status] = :verified
        PkernelJce::GConf.instance.glog.debug "Timestamp verified against signing cert [#{signingCert.subject}]"

        result[:signer] = { }
        result[:signer][:cert] = signingCert
        result[:signer][:chain] = token.getCertificates.to_a

      rescue Exception => ex
        result[:signature_status] = :failed
        result[:signature_status_details] = ex.message
      end
    end
    # end verifyResp

    req = opts[:request]
    if not token.nil? and not req.nil?

      source = opts[:data]
      if not source.nil?
        sfile = source[:file]
        sbin = source[:bin]
      end

      if not (sfile.nil? or sfile.empty?) or not sbin.nil?

        dgst = PkernelJce::BcHelpers.find_digest_calculator(req.getMessageImprintAlgOID)
        if not dgst.nil?
          if not (sfile.nil? or sfile.empty?)
            PkernelJce::GConf.instance.glog.debug "Calculating hash for source '#{sfile}'"
            b = Java::byte[10240].new
            fis = java.io.FileInputStream.new(sfile)
            while((read = fis.read(b,0,b.length)) != -1)
              dgst.getOutputStream.write(b,0,read)
            end
            dgst.getOutputStream.close

          elsif not sbin.nil?
            PkernelJce::GConf.instance.glog.debug "Calculating hash for source from memory"
            dgst.getOutputStream.write(sbin.to_java_bytes)
            dgst.getOutputStream.close
          end

          if not java.util.Arrays.equals(dgst.digest, req.getMessageImprintDigest)
            raise PkernelJce::Error, "Source digest is different from request! Source file is not the original data sent for timestamp"
          else
            PkernelJce::GConf.instance.glog.debug "Source file hash matched request digest."
          end
        else
          PkernelJce::GConf.instance.glog.warn "Failed to initialize the hashing algo for source verification. Source verification shall be skipped."
        end
      end
      # end not source.nil?

      begin
        resp.validate(req)
        result[:request_validation] = :verified
        result[:digest] = info.getMessageImprintDigest
        result[:digest_algo] = info.getMessageImprintAlgOID
        PkernelJce::GConf.instance.glog.debug "Timestamp response verified against timestamp request. Checked [Nonce, Status, Digest, Hash Engine, Policy, Signing Certificates]"
      rescue Exception => ex
        result[:request_validation] = :failed
        result[:request_validation_details] = ex.message
      end
    end


    if not info.nil?
      acc = info.getAccuracy
      result[:accuracy] = {}
      result[:accuracy][:seconds] = acc.getSeconds.nil? ? 0 : acc.getSeconds.value
      result[:accuracy][:milis] = acc.getMillis.nil? ? 0 : acc.getMillis.value
      result[:accuracy][:micros] = acc.getMicros.nil? ? 0 : acc.getMicros.value
      time = info.getGenTime
      result[:time] = time
      nonce = info.getNonce
      result[:nonce] = nonce.to_s(16)
      serial = info.getSerialNumber
      result[:serial] = serial.to_s(16)
      policy = info.getPolicy
      result[:policy] = policy
      tsa = info.getTsa
      result[:tsa_name] = tsa.name.to_s
      ordered = info.isOrdered
      result[:ordered] = ordered
    end

  else
    # status is NOT granted or granted with mods!
    result[:reason] = resp.getFailInfo
    result[:reasonMsg] = resp.getStatusString
  end
  # if status is granted or granted with mods
  
  result
  
end