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