Skip to content

GMime 4.0 Plan #74

Open
Open

Description

@jstedfast

GMime 4.0 ideas:

  • Privatize all object structs to allow for future expansion
  • Rename g_mime_object_encode() to g_mime_object_prepare() for API consistency with MimeKit?
  • Add a GMimeVisitor class and GMimeObjectClass::accept virtual method? If we do, we'll also want:
    • Add GMimeMultipartAlternative
    • Add GMimeMultipartRelated
    • Add GMimeMultipartReport
    • Add GMimeMessageDeliveryStatus
    • Add GMimeMessageDispositionNotification
    • Add GMimeTextRfc822Headers
  • Add g_mime_message_get_text_body() and g_mime_message_get_html_body() like MimeKit has? These would replace g_mime_message_get_body()
  • Update GMimeSignature and GMimeCertificate to use a gint64 (internally at most) or GDateTime (public API for sure and maybe internally as well?) for the timestamps. (issue GMimeSignature created and expires are time_t, fail in Y2038 on platforms with 32-bit signed time_t #68 and issue in GMime 4.0, timestamps should use some sort of robust/native GLib representations #73)
  • Merge GMimeDecryptFlags and GMimeVerifyFlags (issue in GMime 4.0, consolidate GMimeVerifyFlags and GMimeDecryptFlags as GMimeCryptoFlags #70)?
  • Add support for application/pkcs7-mime; smime-type=compressed-data (issue handle PKCS#7 CompressedData #66)
  • Add support for application/pkcs7-mime; smime-type=authEnveloped-data (issue handle PKCS#7 authEnveloped-data #65)
    • Unfortunately, this seems to require GpgSM v2.5.20 and likely more like v2.5.24 to get it to actually work and I'm stuck on 2.4.8 as of Oct 28 2026.
  • Can we get rid of g_mime_stream_close()? Disposing of the stream can (and already does to an extent) take the place of close(). This might eliminate confusion of reading/writing to a closed stream.
  • Should g_mime_crypto_context_sign() take an InternetAddressMailbox instead of const char *userid? Same idea for g_mime_crypto_context_encrypt() for both the userid and recipients arguments.
  • Should g_mime_object_write_to_stream() be fixed to return gint64?
  • Should GMimeStream's read/write functions take GError and/or GCancellation arguments? Same for GMimeParser APIs? And g_mime_object_write_to_stream(), etc.

Activity

  1. jstedfast commented on Dec 21, 2019

    @jstedfast
    OwnerAuthor

    The more I think about it, the more I think I'm probably going to pass on adding a GMimeVisitor API.

    I'm probably also going to pass on the GError and GCancellation stuff as well.

  2. albrechtd commented on Dec 30, 2019

    @albrechtd
    Contributor

    Disclaimer: the remarks below come from the requirements for Balsa as well as for an other project (non-FOSS) I'm working on for my current employer (a German Government agency) which has somewhat different requirements as it is not a MUA.

    Basically, GMime 3.2.4 (the latest for Debian Bullseye) provides almost everything I need – the exception actually is crypto support. From my POV, it would be ideal if GMime would simply provide access to the excellent GpgME data structures. I understand that you want to hide all the complexity of GpgME behind your own interfaces for a painless implementation of trivial use-cases. However, as this approach also completely hides the full flexibility and power of GpgME, the GMime crypto interface is not usable for more complex tasks like mine.

    I presume you want to keep your stripped-down crypto interface in ver 4.0 as to support other projects. In order to make is usable for more demanding use cases, a solution could be adding methods to access to the underlying GpgME objects, plus several callbacks and/or signals. If you want to avoid a mandatory dependency of GMime headers on gpgme.h, you could wrap the “advanced” interfaces into #ifdef GPGME_VERSION, i.e. they are visible only if gpgme.h is included before.

    1. GpgME context manipulation

    GMime provides no access to the properties of the underlying GpgME contexts and is thus unusable for me. It must be possible to configure the crypto engine, including the working folder, flags, etc., plus some more nasty changes of the engine. A method for accessing the GpgME context, e.g. gpgme_ctx_t g_mime_crypto_context_gpgme_ctx(GMimeCryptoContext *ctx), should be sufficient. If a context is created automatically (e.g. for g_mime_multipart_signed_verify() or similar) a callback must be called (or a signal fired) immediately after creating the context. The callback (or signal handler) must receive the GpgME context and the purpose it has been created for.

    2. Key selection for signing and/or encryption

    If I understand the key selection code correctly, it simply returns the first matching key on success, or just bails out with an error. This would be fine in a perfectly ideal world, but fails for the following common cases and is thus not usable:

    1. There is more than one valid key for a certain uid. This happens if e.g.
      • legacy keys which have never expired or been revoked exist in the key ring (according to German laws, access to documents must be provided –depending upon the type of the document– for up to 30 years, so this case is very common),
      • a key is in use for legacy crypto hardware which supports 2k (or even less) keys only (quite common), or where high-grade keys must not be used for security reasons (think of Windows 10 and its nasty “telemetry” spying feature), and a different high-grade key is in use for modern, safe systems (see also item 3 below), etc.
    2. The GpgME key listing does not find a key, because the user simply forgot to add a mail alias to the uid's, because the uid is obfuscated (both very common cases, too), or the crypto operations are performed by a gateway using some kind of “collective key”.
    3. Even if there is exactly one matching key, it may be unusable due to further restrictions (e.g. key size, curve type, etc. – this is a quite special use case; see item 3 below).

    As solution, GMime's key listing must call a callback with a list of keys (i.e. gpgme_key_t) and the reason for calling it (see the Balsa code for an example). The list shall contain

    • in case 1: the matching keys. This callback must always be called;
    • in case 2: all usable (not expired, revoked, etc.) keys. The context might be configured to bail out in this case instead of calling the callback, although I don't see why this behaviour should be of any real-life use;
    • in case 3: the matching (single) key. This should be optional (configurable).

    Furthermore, the key listing mode and properties of the context must be configurable, but this would be covered by solving item 1 above.

    BTW, a key selection based upon InternetAddressMailbox items is really a very bad idea: a typical use case is to configure the key id (instead of the mail address) in user profiles as to force using a specific key, which would of course be impossible when requiring InternetAddressMailbox arguments.

    3. Key properties

    The access to (sub-) key properties in the GMime interface (“GMimeCertificate”) is extremely limited. In my projects, I must have access

    • to all key properties, in particular the flags,
    • to all subkeys, including its properties, in particular (but not limited to) to is_de_vs (German Government classified at “Restricted” level = “VS-NfD”),
    • to all uid's, including its properties, in particular the key signatures and the tofu information.

    Note that this information is required both for key listings (i.e. in the callback outlined above), and for decryption and signature verification data.

    Providing access to the GpgME data via a method, e.g. const gpgme_key_t g_mime_certificate_gpgme_key(GMimeCertificate *cert), should be sufficient.

    4. Signature verification info

    The signature information provided by GMime is incomplete and therefore unusable for me. Access to in particular the PKA data, chain model information, notation and policy data is required. Again, a method like const gpgme_verify_result_t g_mime_signature_gpgme_result(GMimeSignature *sig) should be sufficient.

    5. Decryption result

    The decryption result lacks the flags (e.g. VS-NfD, see item 3 above). Please provide access to the full data, e.g. const gpgme_decrypt_result_t g_mime_decrypt_result_gpgme_result(GMimeDecryptResult *result) or similar.


    Note: the following points are not blockers, but more a wish list. I have implementations for them (using my own GpgME interface, of course), but they might also be of interest for other projects.

    6. RFC 4880 messages

    It would be great if GMime could provide support for “old” RFC 4880 signed and/or encrypted messages. For sending, this should be limited to just signing and/or encrypting a single-part (text/plain) message.

    The interpretation of such parts is a lot more complex, as a message part may contain a mixture of signed and/or encrypted and unsigned/unencrypted data. A common case are mailing list processors which append a few lines of information after the signed stuff, but it is also a method used in attacks (see the Johnny, you are fired! and Re: What's Up Johnny? papers). A method interpreting such message parts therefore should return a list of chunks, e.g. for the simple mailing list example a text “part” with signature information (the original message), plus a text “part” without it (the stuff appended by the list processor).

    7. Autocrypt keys via key id or mailbox

    The Autocrypt code is very nice, but it would be great if I could have a method which loads the minimal key (as requested by the Autocrypt specs) based upon the key id (or mail address, but see the remark about InternetAddressMailbox above), e.g. void g_mime_autocrypt_header_set_keydata_by_id(GMimeAutocryptHeader *ah, const gchar *key_id). However, exporting the minimal key is a little tricky, as it is not supported directly by GpgME, and depends upon the underlying gpg version (see the Enigmail or Balsa sources).

    8. Standards compliance

    I believe that GMime is really well-tested and documented. However, for including GMime in (non-FOSS) projects requiring formal approvals it would be helpful if you could prove that GMime complies with usual safety/security standards like MISRA C:2012 or the SEI CERT C Coding Standard, i.e. if you could provide a test/compliance report from a tool like Flexelint, LDRA or similar – typically not in the toolbox of OSS programmers, though, so this is really a “nice-to-have” topic.

  3. bernhardreiter commented on Mar 3, 2020

    @bernhardreiter

    Would be cool to have support for getting pubkey with https://gnupg.org/WKD (Web key directory).
    It probably just works already when setting the right gpgme options for external key listings, but some examples would be helpful.

  4. sigasigasiga commented on Oct 7, 2021

    @sigasigasiga
    Contributor

    it could be nice to add an ability to copy GMimeObject class. AFAIK it couldn't be implemented in 3.x because of ABI breakage https://www.mail-archive.com/gmime-devel-list@gnome.org/msg00506.html

  5. gouthamkrishnakv commented on Dec 5, 2022

    @gouthamkrishnakv

    Is there a plan to move to Meson or CMake?

    Most GNOME applications do use Meson, and I was thinking of writing meson build files to integrate it into my project. Automake seemed to be difficult and cumbersome for my use-case, and so this might probably make it easier to integrate it later on for future projects, also.

  6. jstedfast commented on Dec 5, 2022

    @jstedfast
    OwnerAuthor

    @gauthamkrishna9991 I haven't been keeping up with GNOME development trends for quite a while so haven't even heard of Meson and I haven't used CMake enough to have an opinion on that (although I have at least heard of it).

  7. gouthamkrishnakv commented on Dec 7, 2022

    @gouthamkrishnakv

    @jstedfast Okay, cool cool. I'll probably have to look into integrating Autotools into my project, then. I was thinking maybe you could check this out for a major version bump, as this would be a good time to check out meson itself.

    Just to give you an idea, this is how a meson.build file looks like (in project root).

    project('gmime', ['c', 'cpp'], version: '4.00')
    
    # Dependencies
    x1_dep =  dependency('x1', version: '>= 2.0', fallback = ['x1', 'x1_dep'], required: true)
    
    # Go inside 'gmime', run 'gmime/meson.build`
    subdir('gmime')
    # Inside `gmime/meson.build`: sources = files('gmime.c', 'gmime-message.c', ...)
    
    # Initialize Shared Library
    shlib = shared_lib('gmime',
      dependencies: [x1_dep],
      install: true,
    )
    
    # Run tests
    subdir('tests')
    
    # Declare GMime Dependency, Everything else is taken care of by Meson.
    gmime_dep = declare_dependency(
      include_directories: include_directories('gmime'),
      link_with: shlib
    )

    In any case, I'll end up checking for Autotools integration for my personal project, as that seems to be your preference.

  8. c-alpha commented on Jan 11, 2023

    @c-alpha

    @gauthamkrishna9991 I haven't been keeping up with GNOME development trends for quite a while so haven't even heard of Meson and I haven't used CMake enough to have an opinion on that (although I have at least heard of it).

    In https://github.com/astroidmail/astroid we migrated from meson to CMake. Automake is certainly showing its age. That said, my recommendation would be to go with CMake.

  9. dagle commented on May 10, 2023

    @dagle
    Contributor

    Refcounted format and parser options.
    Atm these boxed types are then copied multiple times when used.
    I propose that we should reference count these object instead of copying.

    If a user wants to pull out parser from a structure, change a values without wanting it propagated,
    a g_mime_(format|parser)_options_copy should be used (which already exists for format).

    It also simplifies the semantics for callbacks and NotifyDestroy, since copy wouldn't
    copy the callback and clone (ref) would just increase a reference counter.

    These change need to be stated in the doc strings and changing the clone/free to ref/unref
    should also make it more clear what is going on.

    I have written a test version with these changes and I haven't run into any problems so far.

  10. jstedfast commented on Aug 31, 2023

    @jstedfast
    OwnerAuthor

    @dagle

    The reason they are cloned instead of ref-counted is because GMimeHeader (and other objects that keep refs to them) need to be sure they haven't changed since they were referenced.

  11. jstedfast commented on Oct 28, 2026

    @jstedfast
    OwnerAuthor

    @gouthamkrishnakv My v4.0-dev branch has moved to Meson.

  12. jstedfast commented on Oct 29, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd

    1. GpgME context manipulation

    I've added ways to get access to the gpgme_x_t types:

    • g_mime_gpg_context_get_gpgme_ctx()
    • g_mime_pkcs7_context_get_gpgme_ctx()
    • g_mime_certificate_get_gpgme_key()
    1. Key selection for signing and/or encryption

    Let's figure out a solution for this.

    1. Key properties

    Yep. See the new g_mime_certificate_get_gpgme_key() function.

    1. Signature verification info

    Yes, this is a good idea - I'll look into adding this for v4.0.

    1. Decryption result

    Sure.

    1. RFC 4880 messages

    GMime has had detection for this, but yea, it's kind of a pain. I'll see if I can figure something out.

    1. Autocrypt keys via key id or mailbox

    @dkg implemented Autocrypt for GMime. I know very little about it, but I'm open to API suggestions.

    I think I saw something about an Autocrypot v2 spec being worked on?

    1. Standards compliance

    That's gonna be hard....

  13. albrechtd commented on Oct 30, 2026

    @albrechtd
    Contributor

    @albrechtd

    1. GpgME context manipulation

    I've added ways to get access to the gpgme_x_t types:

    • g_mime_gpg_context_get_gpgme_ctx()
    • g_mime_pkcs7_context_get_gpgme_ctx()
    • g_mime_certificate_get_gpgme_key()

    Hmmm, to be honest, I still don't understand why you basically wrap parts of the GpgME interface (which has everything required) into an extra layer of complexity which enlarges the code, adds chances for bugs, and supports just the very basic operations, i.e. requires to expose the underlying interfaces for any non-trivial use case anyway. IMHO, using the GpgME interface directly would be by far more flexible and straightforward.

    Returning the context as void * in a public interface which the caller is expected to cast is a really bad idea which may lead to all sorts of nasty bugs (see e.g. MISRA C, Rule 11.5). The return value must be a gpgme_ctx_t!

    Furthermore, it doesn't make sense to have two methods returning the gpgme_ctx_t – the latter includes the gpgme_protocol_t, so if you really want to keep the extra complexity (which I strongly discourage) the parent object should be used.

    1. Key selection for signing and/or encryption

    Let's figure out a solution for this.

    GpgME has everything for writing a proper callback function. Use the GpgME stuff verbatim, and you're done.

    1. Key properties

    Yep. See the new g_mime_certificate_get_gpgme_key() function.

    Same flaw as above - the return value must be a gpgme_key_t! Again, I cannot see any good reason for re-inventing a rather limited version of GpgME's key management.

    1. Signature verification info

    Yes, this is a good idea - I'll look into adding this for v4.0.

    Again, GpgME has everything…

    1. Decryption result

    Sure.

    …ditto.

    1. RFC 4880 messages

    GMime has had detection for this, but yea, it's kind of a pain. I'll see if I can figure something out.

    Unfortunately, I still see lots of RFC 9580 (was '4880) stuff in the wild, so this would be really helpful.

    An other very interesting extension would be support for RFC 9788 protected headers, btw – afaik not widely (if at all) used yet, though. Thunderbird seems to support a meanwhile withdrawn proposal in some versions; an interesting approach, but not worth implementing any more IMHO.

    1. Autocrypt keys via key id or mailbox

    @dkg implemented Autocrypt for GMime. I know very little about it, but I'm open to API suggestions.

    I think I saw something about an Autocrypot v2 spec being worked on?

    Good question… I'm not aware of that. Do you have any pointers?

    1. Standards compliance

    That's gonna be hard....

    Well, even a rather simple static analyser like cppcheck can detect lots of issues. Access to a more sophisticated tool like LDRA, Eclair, PClint Plus, … would of course be helpful. IMHO, implementing the rules and recommendations of the C CERT Secure Coding Standard would be an excellent starting point!

  14. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd

    I cannot see any good reason for re-inventing a rather limited version of GpgME's key management.

    The original idea was to abstract things out so a different backend could be used. Given that it's not super likely, I could possibly remove the abstraction layer.

    I'll look into something like cppcheck.

  15. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd FWIW, I've been working on adding fuzz tests and as part of my port of to Meson, I now have unit tests running under ASan and UBSan and things are coming back clean.

  16. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd I've added CodeQL and cppcheck GitHub workflows now.

  17. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd Ripping out the GMime abstractions over gpgme_ctx_t was fairly quick & doable and I just pushed that. I'm working on implementing inline PGP support now using the existing OpenPGP filter logic.

  18. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @albrechtd Inline-PGP support has been added

  19. jstedfast commented on Oct 30, 2026

    @jstedfast
    OwnerAuthor

    @dagle I've decided you were right to suggest ref counting GMimeFormatOptions and GMimeParserOptions - I'm going to keep the clone API as well, to satisfy the needs I have, but that doesn't mean we can't ref-count them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions