class Gem::Security::Policy

:nodoc:
:nodoc:

def check_cert(signer, issuer, time)

def check_cert(signer, issuer, time)
  raise Gem::Security::Exception, 'missing signing certificate' unless
    signer
  message = "certificate #{signer.subject}"
  if not_before = signer.not_before and not_before > time
    raise Gem::Security::Exception,
          "#{message} not valid before #{not_before}"
  end
  if not_after = signer.not_after and not_after < time
    raise Gem::Security::Exception, "#{message} not valid after #{not_after}"
  end
  if issuer and not signer.verify issuer.public_key
    raise Gem::Security::Exception,
          "#{message} was not issued by #{issuer.subject}"
  end
  true
end

def check_chain(chain, time)

def check_chain(chain, time)
  raise Gem::Security::Exception, 'missing signing chain' unless chain
  raise Gem::Security::Exception, 'empty signing chain' if chain.empty?
  begin
    chain.each_cons 2 do |issuer, cert|
      check_cert cert, issuer, time
    end
    true
  rescue Gem::Security::Exception => e
    raise Gem::Security::Exception, "invalid signing chain: #{e.message}"
  end
end

def check_data(public_key, digest, signature, data)

def check_data(public_key, digest, signature, data)
  raise Gem::Security::Exception, "invalid signature" unless
    public_key.verify digest, signature, data.digest
  true
end

def check_key(signer, key)

def check_key(signer, key)
  unless signer and key
    return true unless @only_signed
    raise Gem::Security::Exception, 'missing key or signature'
  end
  raise Gem::Security::Exception,
    "certificate #{signer.subject} does not match the signing key" unless
      signer.public_key.to_pem == key.public_key.to_pem
  true
end

def check_root(chain, time)

def check_root(chain, time)
  raise Gem::Security::Exception, 'missing signing chain' unless chain
  root = chain.first
  raise Gem::Security::Exception, 'missing root certificate' unless root
  raise Gem::Security::Exception,
        "root certificate #{root.subject} is not self-signed " +
        "(issuer #{root.issuer})" if
    root.issuer != root.subject
  check_cert root, root, time
end

def check_trust(chain, digester, trust_dir)

def check_trust(chain, digester, trust_dir)
  raise Gem::Security::Exception, 'missing signing chain' unless chain
  root = chain.first
  raise Gem::Security::Exception, 'missing root certificate' unless root
  path = Gem::Security.trust_dir.cert_path root
  unless File.exist? path
    message = "root cert #{root.subject} is not trusted".dup
    message << " (root of signing cert #{chain.last.subject})" if
      chain.length > 1
    raise Gem::Security::Exception, message
  end
  save_cert = OpenSSL::X509::Certificate.new File.read path
  save_dgst = digester.digest save_cert.public_key.to_s
  pkey_str = root.public_key.to_s
  cert_dgst = digester.digest pkey_str
  raise Gem::Security::Exception,
        "trusted root certificate #{root.subject} checksum " +
        "does not match signing root certificate checksum" unless
    save_dgst == cert_dgst
  true
end

def initialize(name, policy = {}, opt = {})

def initialize(name, policy = {}, opt = {})
  @name = name
  @opt = opt
  # Default to security
  @only_signed   = true
  @only_trusted  = true
  @verify_chain  = true
  @verify_data   = true
  @verify_root   = true
  @verify_signer = true
  policy.each_pair do |key, val|
    case key
    when :verify_data   then @verify_data   = val
    when :verify_signer then @verify_signer = val
    when :verify_chain  then @verify_chain  = val
    when :verify_root   then @verify_root   = val
    when :only_trusted  then @only_trusted  = val
    when :only_signed   then @only_signed   = val
    end
  end
end

def inspect # :nodoc:

:nodoc:
def inspect # :nodoc:
  ("[Policy: %s - data: %p signer: %p chain: %p root: %p " +
   "signed-only: %p trusted-only: %p]") % [
     @name, @verify_chain, @verify_data, @verify_root, @verify_signer,
     @only_signed, @only_trusted
   ]
end

def subject(certificate) # :nodoc:

:nodoc:
def subject(certificate) # :nodoc:
  certificate.extensions.each do |extension|
    next unless extension.oid == 'subjectAltName'
    return extension.value
  end
  certificate.subject.to_s
end

def verify(chain, key = nil, digests = {}, signatures = {},

def verify(chain, key = nil, digests = {}, signatures = {},
           full_name = '(unknown)')
  if signatures.empty?
    if @only_signed
      raise Gem::Security::Exception,
        "unsigned gems are not allowed by the #{name} policy"
    elsif digests.empty?
      # lack of signatures is irrelevant if there is nothing to check
      # against
    else
      alert_warning "#{full_name} is not signed"
      return
    end
  end
  opt       = @opt
  digester  = Gem::Security.create_digest
  trust_dir = opt[:trust_dir]
  time      = Time.now
  _, signer_digests = digests.find do |algorithm, file_digests|
    file_digests.values.first.name == Gem::Security::DIGEST_NAME
  end
  if @verify_data
    raise Gem::Security::Exception, 'no digests provided (probable bug)' if
      signer_digests.nil? or signer_digests.empty?
  else
    signer_digests = {}
  end
  signer = chain.last
  check_key signer, key if key
  check_cert signer, nil, time if @verify_signer
  check_chain chain, time if @verify_chain
  check_root chain, time if @verify_root
  if @only_trusted
    check_trust chain, digester, trust_dir
  elsif signatures.empty? and digests.empty?
    # trust is irrelevant if there's no signatures to verify
  else
    alert_warning "#{subject signer} is not trusted for #{full_name}"
  end
  signatures.each do |file, _|
    digest = signer_digests[file]
    raise Gem::Security::Exception, "missing digest for #{file}" unless
      digest
  end
  signer_digests.each do |file, digest|
    signature = signatures[file]
    raise Gem::Security::Exception, "missing signature for #{file}" unless
      signature
    check_data signer.public_key, digester, signature, digest if @verify_data
  end
  true
end

def verify_signatures(spec, digests, signatures)

def verify_signatures(spec, digests, signatures)
  chain = spec.cert_chain.map do |cert_pem|
    OpenSSL::X509::Certificate.new cert_pem
  end
  verify chain, nil, digests, signatures, spec.full_name
  true
end