module NetPGP

Constants

DEFAULT_PASSPHRASE_PROVIDER
PARSE_KEYRING

Public Class Methods

add_subkey_signature(key, subkey) click to toggle source

Add a subkey binding signature (type 0x18) to a key. Note that this should be used for encryption subkeys.

@param key [LibNetPGP::PGPKey] @param subkey [LibNetPGP::PGPKey]

# File lib/netpgp/highlevel/utils.rb, line 90
def self.add_subkey_signature(key, subkey)
  sig = nil
  sigoutput = nil
  mem_sig = nil
  begin
    sig = LibNetPGP::pgp_create_sig_new
    LibNetPGP::pgp_sig_start_subkey_sig(sig, key[:key][:pubkey], subkey[:key][:pubkey], :PGP_SIG_SUBKEY)
    LibNetPGP::pgp_add_time(sig, subkey[:key][:pubkey][:birthtime], 'birth')
    # TODO expiration
    LibNetPGP::pgp_add_issuer_keyid(sig, key[:sigid])
    LibNetPGP::pgp_end_hashed_subpkts(sig)

    sigoutput_ptr = FFI::MemoryPointer.new(:pointer)
    mem_sig_ptr = FFI::MemoryPointer.new(:pointer)
    LibNetPGP::pgp_setup_memory_write(sigoutput_ptr, mem_sig_ptr, 128)
    sigoutput = LibNetPGP::PGPOutput.new(sigoutput_ptr.read_pointer)
    LibNetPGP::pgp_write_sig(sigoutput, sig, key[:key][:pubkey], key[:key][:seckey])
    mem_sig = LibNetPGP::PGPMemory.new(mem_sig_ptr.read_pointer)
    sigpkt = LibNetPGP::PGPSubPacket.new
    sigpkt[:length] = LibNetPGP::pgp_mem_len(mem_sig)
    sigpkt[:raw] = LibNetPGP::pgp_mem_data(mem_sig)
    LibNetPGP::pgp_add_subpacket(subkey, sigpkt)
  ensure
    LibNetPGP::pgp_create_sig_delete(sig) if sig
    LibNetPGP::pgp_teardown_memory_write(sigoutput, mem_sig) if mem_sig
  end
end
bignum_byte_count(bn) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 3
def self.bignum_byte_count(bn)
  # Note: This probably assumes that the ruby implementation
  # uses the same BN representation that libnetpgp does.
  # It may be better to convert and use BN_num_bytes (or bits).
  bn.to_s(16).length / 2
end
keys_to_native_keyring(keys, native) click to toggle source
# File lib/netpgp/highlevel/keyring.rb, line 222
def self.keys_to_native_keyring(keys, native)
  raise if not native[:keys].null?

  for key in keys
    native_key = LibNetPGP::PGPKey.new
    key.to_native_key(native_key)
    LibNetPGP::dynarray_append_item(native, 'key', LibNetPGP::PGPKey, native_key)
  end
end
load_keys(data, armored=true, &passphrase_provider) click to toggle source
# File lib/netpgp/highlevel/keyring.rb, line 191
def self.load_keys(data, armored=true, &passphrase_provider)
  # Just for readability
  print_errors = 0
  stream_mem = LibC::calloc(1, LibNetPGP::PGPStream.size)
  # This will free the above memory (PGPStream is a ManagedStruct)
  stream = LibNetPGP::PGPStream.new(stream_mem)
  stream[:readinfo][:accumulate] = 1
  LibNetPGP::pgp_parse_options(stream, :PGP_PTAG_SS_ALL, :PGP_PARSE_PARSED)

  # This memory will be GC'd
  mem = FFI::MemoryPointer.new(:uint8, data.bytesize)
  mem.write_bytes(data)

  LibNetPGP::pgp_reader_set_memory(stream, mem, mem.size)
  state = {keys: [], errors: []}
  provider = block_given? ? passphrase_provider : DEFAULT_PASSPHRASE_PROVIDER
  callback = NetPGP::PARSE_KEYRING.curry[state][provider]
  LibNetPGP::pgp_set_callback(stream, callback, nil)
  LibNetPGP::pgp_reader_push_dearmour(stream) if armored
  if LibNetPGP::pgp_parse(stream, print_errors) != 1
    state[:errors].push('pgp_parse failed')
  end
  LibNetPGP::pgp_reader_pop_dearmour(stream) if armored

  errors = stream_errors(stream)
  state[:errors].push(errors) if errors.any?

  raise state[:errors].join("\n") if state[:errors].any?
  state[:keys]
end
mpi_from_native(native) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 25
def self.mpi_from_native(native)
  mpi = {}
  native.members.each {|member|
    if native[member].null?
      mpi[member] = nil
    else
      mpi[member] = LibNetPGP::bn2hex(native[member]).hex
    end
  }
  mpi
end
mpi_to_native(mpi, native) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 51
def self.mpi_to_native(mpi, native)
  mpi.each {|name,value|
    if mpi[name] == nil
      native[name] = nil
    else
      native[name] = LibNetPGP::num2bn(value)
    end
  }
end
mpis_from_native(alg, native) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 37
def self.mpis_from_native(alg, native)
  case alg
    when :PGP_PKA_RSA, :PGP_PKA_RSA_ENCRYPT_ONLY, :PGP_PKA_RSA_SIGN_ONLY
      material = native[:key][:rsa]
    when :PGP_PKA_DSA
      material = native[:key][:dsa]
    when :PGP_PKA_ELGAMAL
      material = native[:key][:elgamal]
    else
      raise "Unsupported PK algorithm: #{alg}"
  end
  NetPGP::mpi_from_native(material)
end
mpis_to_native(alg, mpi, native) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 61
def self.mpis_to_native(alg, mpi, native)
  case alg
  when :PGP_PKA_RSA, :PGP_PKA_RSA_ENCRYPT_ONLY, :PGP_PKA_RSA_SIGN_ONLY
    material = native[:key][:rsa]
  when :PGP_PKA_DSA
    material = native[:key][:dsa]
  when :PGP_PKA_ELGAMAL
    material = native[:key][:elgamal]
  else
    raise "Unsupported PK algorithm: #{alg}"
  end
  # Ensure we're not leaking memory from a prior call.
  # This just frees all the BNs.
  if native.is_a?(LibNetPGP::PGPSecKey)
    LibNetPGP::pgp_seckey_free(native)
  elsif native.is_a?(LibNetPGP::PGPPubKey)
    LibNetPGP::pgp_pubkey_free(native)
  else
    raise
  end
  NetPGP::mpi_to_native(mpi, material)
end
stream_errors(stream) click to toggle source
# File lib/netpgp/highlevel/utils.rb, line 10
def self.stream_errors(stream)
  error_ptr = stream[:errors]

  errors = []
  until error_ptr.null?
    error = LibNetPGP::PGPError.new(error_ptr)

    error_desc = "#{error[:file]}:#{error[:line]}: #{error[:errcode]} #{error[:comment]}"
    errors.push(error_desc)

    error_ptr = error[:next]
  end
  errors
end
verify(keys, data, armored=true) click to toggle source
# File lib/netpgp/highlevel/keyring.rb, line 232
def self.verify(keys, data, armored=true)
  native_keyring_ptr = LibC::calloc(1, LibNetPGP::PGPKeyring.size)
  native_keyring = LibNetPGP::PGPKeyring.new(native_keyring_ptr)
  NetPGP::keys_to_native_keyring(keys, native_keyring)

  pgpio = LibNetPGP::PGPIO.new
  pgpio[:outs] = LibC::fdopen($stdout.to_i, 'w')
  pgpio[:errs] = LibC::fdopen($stderr.to_i, 'w')
  pgpio[:res] = pgpio[:errs]

  data_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
  data_buf.write_bytes(data)

  # pgp_validate_mem frees this
  mem_ptr = LibC::calloc(1, LibNetPGP::PGPMemory.size)
  mem = LibNetPGP::PGPMemory.new(mem_ptr)
  LibNetPGP::pgp_memory_add(mem, data_buf, data_buf.size)

  # ManagedStruct, this frees itself
  result_ptr = LibC::calloc(1, LibNetPGP::PGPValidation.size)
  result = LibNetPGP::PGPValidation.new(result_ptr)

  ret = LibNetPGP::pgp_validate_mem(pgpio, result, mem, nil, armored ? 1 : 0, native_keyring)
  ret == 1
end