FFI parity: 89 new bindings — verification, key certification, security profiles#94
Open
ronaldtse wants to merge 14 commits into
Open
FFI parity: 89 new bindings — verification, key certification, security profiles#94ronaldtse wants to merge 14 commits into
ronaldtse wants to merge 14 commits into
Conversation
Attach (with optional-symbol probing) the librnp functions needed for verification/signature introspection, key certification, security profile rules, key inspection and misc utilities, along with the related constants.
Verify op: flags= (RNP_VERIFY_*), format (literal data format), recipient and symenc enumeration (recipients, used_recipient, symencs, used_symenc) via the new Recipient and Symenc value objects. Signature: signature_type, fingerprint, expiration_time, features, key_flags, key_expiration, primary_uid?, key_server(+prefs), revoker, revocation_reason, trust_level, preferred_ciphers/hashes/compressions, valid?, export, and the subpacket API (each_subpacket, subpackets, subpacket) via the new Signature::Subpacket value object.
KeySignature wraps the editable key signature handle created by Key#start_certification, Key#start_direct_signature and Key#start_revocation_signature. It supports setting the hash, creation time, key flags/expiration, features, preferred algorithms, primary userid flag, key server (+preferences), revocation reason, designated revoker and trust level, and is finalized with #sign. Also Key#revocation_signature, Key#remove_signature (single) and Key#remove_signatures (filtered by invalid/unknown-key/non-self flags).
Rnp#add_security_rule, #security_rule and #remove_security_rule wrap the librnp security rule API (0.16.3+), allowing to override the default algorithm security levels (e.g. to accept SHA1 signatures). Rnp#timestamp= wraps rnp_set_timestamp.
New Key methods: version, expired?, valid?, valid_till, revokers, primary_fingerprint and the secret key protection information (protection_type, protection_mode, protection_cipher, protection_hash, protection_iterations).
- Rnp.backend_string and Rnp.backend_version (crypto backend info) - Rnp#request_password (via the ffi password provider, securely clearing the buffer with rnp_buffer_clear) - Generate#request_password= (request key protection password via the password provider) - Encrypt#flags= (RNP_ENCRYPT_NOWRAP) - Output.to_armor, Output#armor_line_length= and Output#finish - Rnp.dump_packets (human-readable packet dump)
rnp_output_destroy() accesses the base output when destroying an armored output (propagating the keep flag and writing the armor trailer), so the armored output must be destroyed first. With two independent AutoPointers the GC could finalize the base output first, corrupting the heap (observed as glibc malloc aborts in CI, e.g. in the GC-forcing z_spec). Coordinate the two finalizers via a shared state so the armored output is always destroyed before the base output, exactly once, while keeping the base output usable on its own.
Sign, Verify and Encrypt operations did not reference their input and output objects, so a caller creating an operation with temporary Input/Output objects could have them garbage collected before execute(), resulting in a use-after-free read (observed under GC.stress).
The signature removal specs are set up via the key certification API (0.18+), but their inner 'skip: false' metadata (the removal API itself exists in 0.17.x) overrode the outer skip and ran them anyway, raising FeatureNotAvailableError. Drop the inner skip metadata. Also, rnp_signature_is_valid() only learnt to return the validation status of document signatures and to revalidate key signatures (RNP_SIGNATURE_REVALIDATE) in 0.18.0. Gate the affected specs on the new 'signature-validity-status' feature.
Attach the last 23 exported-but-unbound librnp functions, completing FFI parity: the uid API, key lifecycle (revoke, expiration, default key, autocrypt/revocation export), op file metadata and protection info, I/O stream helpers and Curve25519 bit tweaking, along with the related constants. Symbols newer than the minimum supported librnp (0.15.2) - the stdio helpers and 25519 tweaking - go through the optional-symbol probing.
Extend the UserID object with data, type, primary?, valid?, revocation_signature and remove (wraps rnp_uid_remove). The uid handle references the owning key internally, so the key is now retained by the UserID to prevent use-after-free if the key object is garbage collected first.
- Key#revoke (with optional hash, reason code and text) - Key#set_expiration - Key#default_key (usage-based default key/subkey selection) - Key#export_autocrypt (minimal Autocrypt export, binary or base64) - Key#export_revocation (standalone revocation signature export) - Key#x25519_bits_tweak / #x25519_bits_tweaked? (advanced Curve25519 secret key bit tweaking; the latter returns true when the bits are correctly set)
- Sign#file_name= / #file_mtime= and Encrypt#file_name= / #file_mtime= (embedded into the literal data packet) - Encrypt#aead_bits= (AEAD chunk size bits) - Verify#protection_info (encryption mode, cipher and integrity status of the processed message) - Verify#file_info (embedded file name and modification time)
- Output.to_file (with overwrite and atomic random-name options) - Output#pipe_from (copy an input to the output) - Input.from_stdin and Output.to_stdout (convenience-only wrappers, feature-gated)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FFI-parity pass against librnp 0.18.1/main. The gem attaches FFI functions through an optional-probing hash (with
HAVE_*constants); an audit against the 296-symbol FFI surface found 112 genuinely unbound exported functions. This PR binds 89 of them with full specs. (Remaining 23: 4 deliberate skips — stdio helpers and Curve25519 tweak internals — and 19 deprioritized items listed below. The crypto-refresh/PQC symbols are not exported by default builds and are not bound.)What was added
Verify#flags=/#format; recipient enumeration (Rnp::Verify::Recipientwith keyid/alg,used_recipient) and symenc twins (cipher/aead/hash/s2k);Rnp::Signaturegainssignature_type,fingerprint,expiration_time,features,key_flags,key_expiration,primary_uid?,key_server(+prefs),revoker,revocation_reason,trust_level,preferred_ciphers/hashes/compressions,valid?(revalidate:),export(armored:); subpacket API as eager value objects (Rnp::Signature::Subpacket: type/data/hashed?/critical?) witheach_subpacket/subpackets/subpacket();Key#remove_signature.Rnp::KeySignaturebuilder (allrnp_key_signature_set_*+add_preferred_*+#sign), created viaKey#start_certification(uid, type:),#start_direct_signature,#start_revocation_signature;Key#remove_signatures(invalid:, unknown_key:, non_self:);Key#revocation_signature.lib/rnp/security.rb):Rnp#add_security_rule(type:, name:, level:, from:, override:, usage:),#security_rule,#remove_security_rule,#timestamp=— feature-gated viaHAVE_*. Spec demonstrates the real semantics: SHA-1 verification rejected by default → allowed via override rule → rejected again after removal (librnp's rules gate hash/cipher verification, not key sizes).Key#version,#expired?,#valid?,#valid_till,#revokers,#primary_fingerprint,#protection_type/mode/cipher/hash/iterations.Rnp.backend_string/backend_version,Rnp#request_password(context, key:)(buffer securely cleared),Generate#request_password=,Encrypt#flags=(NOWRAP),Output.to_armor+#armor_line_length=+#finish,Rnp.dump_packets.Verification (macOS arm64)
Remaining (23)
rnp_input_from_stdin,rnp_output_to_stdout,rnp_key_25519_bits_tweak(ed).rnp_uid_get_*,rnp_uid_remove),rnp_key_revoke/set_expiration/get_default_key/export_autocrypt/export_revocation, op file name/mtime setters,rnp_op_encrypt_set_aead_bits,rnp_op_verify_get_protection_info,rnp_output_pipe/to_file.