lib/rnp/key.rb in rnp-1.0.4 vs lib/rnp/key.rb in rnp-1.0.5
- old
+ new
@@ -1,14 +1,15 @@
# frozen_string_literal: true
-# (c) 2018 Ribose Inc.
+# (c) 2018-2020 Ribose Inc.
require 'ffi'
require 'rnp/error'
require 'rnp/ffi/librnp'
require 'rnp/utils'
+require 'rnp/userid'
class Rnp
# Class that represents a PGP key (potentially encompassing both the public
# and private portions).
class Key
@@ -57,10 +58,17 @@
# @return [String]
def grip
string_property(:rnp_key_get_grip)
end
+ # Get the primary grip of the key (for subkeys)
+ #
+ # @return [String]
+ def primary_grip
+ string_property(:rnp_key_get_primary_grip)
+ end
+
# Get the primary userid of the key
#
# @return [String]
def primary_userid
string_property(:rnp_key_get_primary_uid)
@@ -80,10 +88,42 @@
# @return [Array<String>]
def userids
each_userid.to_a
end
+ # Enumerate each {UserID} for this key.
+ #
+ # @return [self, Enumerator]
+ def each_uid(&block)
+ block or return enum_for(:uid_iterator)
+ uid_iterator(&block)
+ self
+ end
+
+ # Get a list of {UserID}s for this key.
+ #
+ # @return [Array<UserID>]
+ def uids
+ each_uid.to_a
+ end
+
+ # Enumerate each {Signature} for this key.
+ #
+ # @return [self, Enumerator]
+ def each_signature(&block)
+ block or return enum_for(:signature_iterator)
+ signature_iterator(&block)
+ self
+ end
+
+ # Get a list of {Signature}s for this key.
+ #
+ # @return [Array<Signature>]
+ def signatures
+ each_signature.to_a
+ end
+
# Add a userid to a key.
#
# @param userid [String] the userid to add
# @param hash (see Sign#hash=)
# @param expiration_time (see Sign#expiration_time=)
@@ -263,10 +303,138 @@
ensure
LibRnp.rnp_buffer_destroy(presult)
end
end
+ # Unload this key.
+ #
+ # @note When both the public and secret portions of this key have been
+ # unloaded, you should no longer interact with this object.
+ #
+ # @param unload_public [Boolean] if true then the public key will be
+ # unloaded
+ # @param unload_secret [Boolean] if true then the secret key will be
+ # unloaded
+ # @return [void]
+ def unload(unload_public: true, unload_secret: true)
+ flags = 0
+ flags |= LibRnp::RNP_KEY_REMOVE_PUBLIC if unload_public
+ flags |= LibRnp::RNP_KEY_REMOVE_SECRET if unload_secret
+ Rnp.call_ffi(:rnp_key_remove, @ptr, flags)
+ end
+
+ # Enumerate each subkey for this key.
+ #
+ # @return [self, Enumerator]
+ def each_subkey(&block)
+ block or return enum_for(:subkey_iterator)
+ subkey_iterator(&block)
+ self
+ end
+
+ # Get a list of all subkeys for this key.
+ #
+ # @return [Array<Key>]
+ def subkeys
+ each_subkey.to_a
+ end
+
+ # Get the type of this key (RSA, etc).
+ #
+ # @return [String]
+ def type
+ string_property(:rnp_key_get_alg)
+ end
+
+ # Get the bit length for this key.
+ #
+ # @return [Integer]
+ def bits
+ pbits = FFI::MemoryPointer.new(:uint32)
+ Rnp.call_ffi(:rnp_key_get_bits, @ptr, pbits)
+ pbits.read(:uint32)
+ end
+
+ # Get the bit length for the q parameter of this DSA key.
+ #
+ # @return [Integer]
+ def qbits
+ pbits = FFI::MemoryPointer.new(:uint32)
+ Rnp.call_ffi(:rnp_key_get_dsa_qbits, @ptr, pbits)
+ pbits.read(:uint32)
+ end
+
+ # Get the curve of this EC key.
+ #
+ # @return [String]
+ def curve
+ string_property(:rnp_key_get_curve)
+ end
+
+ # Query whether this key can be used to perform a certain operation.
+ #
+ # @param op [String,Symbol] the operation to query (sign, etc)
+ # @return [Boolean]
+ def can?(op)
+ pvalue = FFI::MemoryPointer.new(:bool)
+ Rnp.call_ffi(:rnp_key_allows_usage, @ptr, op.to_s, pvalue)
+ pvalue.read(:bool)
+ end
+
+ # Check if this has been revoked.
+ #
+ # @return [Boolean]
+ def revoked?
+ bool_property(:rnp_key_is_revoked)
+ end
+
+ # Check if this revoked key's material was compromised.
+ #
+ # @return [Boolean]
+ def compromised?
+ bool_property(:rnp_key_is_compromised)
+ end
+
+ # Check if this revoked key was retired.
+ #
+ # @return [Boolean]
+ def retired?
+ bool_property(:rnp_key_is_retired)
+ end
+
+ # Check if this revoked key was superseded by another key.
+ #
+ # @return [Boolean]
+ def superseded?
+ bool_property(:rnp_key_is_superseded)
+ end
+
+ # Retrieve the reason for revoking this key, if any.
+ #
+ # @return [String]
+ def revocation_reason
+ string_property(:rnp_key_get_revocation_reason)
+ end
+
+ # Retrieve the creation time of the key
+ #
+ # @return [Time]
+ def creation_time
+ ptime = FFI::MemoryPointer.new(:uint32)
+ Rnp.call_ffi(:rnp_key_get_creation, @ptr, ptime)
+ Time.at(ptime.read(:uint32))
+ end
+
+ # Retrieve the expiration time of the key
+ #
+ # @return [Time]
+ def expiration_time
+ ptime = FFI::MemoryPointer.new(:uint32)
+ Rnp.call_ffi(:rnp_key_get_expiration, @ptr, ptime)
+ Time.at(ptime.read(:uint32))
+ end
+
private
def string_property(func)
pptr = FFI::MemoryPointer.new(:pointer)
Rnp.call_ffi(func, @ptr, pptr)
@@ -311,16 +479,64 @@
LibRnp.rnp_buffer_destroy(puserid)
end
end
end
+ def uid_iterator
+ pcount = FFI::MemoryPointer.new(:size_t)
+ Rnp.call_ffi(:rnp_key_get_uid_count, @ptr, pcount)
+ count = pcount.read(:size_t)
+ pptr = FFI::MemoryPointer.new(:pointer)
+ (0...count).each do |i|
+ Rnp.call_ffi(:rnp_key_get_uid_handle_at, @ptr, i, pptr)
+ begin
+ phandle = pptr.read_pointer
+ puserid = nil
+ next if phandle.nil?
+ Rnp.call_ffi(:rnp_key_get_uid_at, @ptr, i, pptr)
+ puserid = pptr.read_pointer
+ yield UserID.new(phandle, puserid.read_string) unless puserid.null?
+ phandle = nil
+ ensure
+ LibRnp.rnp_uid_handle_destroy(phandle)
+ LibRnp.rnp_buffer_destroy(puserid)
+ end
+ end
+ end
+
+ def signature_iterator
+ pcount = FFI::MemoryPointer.new(:size_t)
+ Rnp.call_ffi(:rnp_key_get_signature_count, @ptr, pcount)
+ count = pcount.read(:size_t)
+ pptr = FFI::MemoryPointer.new(:pointer)
+ (0...count).each do |i|
+ Rnp.call_ffi(:rnp_key_get_signature_at, @ptr, i, pptr)
+ psig = pptr.read_pointer
+ yield Signature.new(psig) unless psig.null?
+ end
+ end
+
def export(public_key: false, secret_key: false, with_subkeys: false, armored: true, output: nil)
flags = 0
flags |= LibRnp::RNP_KEY_EXPORT_ARMORED if armored
flags |= LibRnp::RNP_KEY_EXPORT_PUBLIC if public_key
flags |= LibRnp::RNP_KEY_EXPORT_SECRET if secret_key
flags |= LibRnp::RNP_KEY_EXPORT_SUBKEYS if with_subkeys
Rnp.call_ffi(:rnp_key_export, @ptr, output.ptr, flags)
+ end
+
+ def subkey_iterator
+ pcount = FFI::MemoryPointer.new(:size_t)
+ Rnp.call_ffi(:rnp_key_get_subkey_count, @ptr, pcount)
+ count = pcount.read(:size_t)
+ pptr = FFI::MemoryPointer.new(:pointer)
+ (0...count).each do |i|
+ Rnp.call_ffi(:rnp_key_get_subkey_at, @ptr, i, pptr)
+ begin
+ psubkey = pptr.read_pointer
+ yield Rnp::Key.new(psubkey) unless psubkey.null?
+ end
+ end
end
end # class
end # class