libcups icon indicating copy to clipboard operation
libcups copied to clipboard

S/MIME APIs

Open michaelrsweet opened this issue 2 years ago • 5 comments

The prototype IPP Encrypted Jobs and Documents v1.0 (TRUSTNOONE) specification sends sensitive IPP attributes and document data in S/MIME containers. Since this might be done with OpenSSL or GNU TLS, we need a CUPS API to expose this functionality.

  • [x] Function to convert an IPP attribute (1setOf text(MAX)) to a single string with newlines separating each value - this will allow X.509 certificates in attributes to be used.
  • [x] Function to convert a single string with newlines to an IPP attribute (1setOf text(MAX)) - necessary for servers to advertise their certificates and for clients to provide their certificate.
  • [ ] Function to write an encrypted S/MIME container with attributes, file, X.509 certificate, and optional password
  • [ ] Function to read an encrypted S/MIME container using a private key and optional password, producing attributes and an optional file (preferably with a callback vs. writing directly to disk)

The read/write functions should support the typical IO callback (like the IPP functions do).

michaelrsweet avatar May 16 '23 15:05 michaelrsweet

Proposed API:

// <cups/ipp.h>
extern ipp_attribute_t *ippAddCredentialsString(ipp_t *ipp, ipp_tag_t group_tag, const char *name, const char *credentials) _CUPS_PUBLIC;
extern char *ippCopyCredentialsString(ipp_attribute_t *attr) _CUPS_PUBLIC;

// <cups/smime.h>
typedef struct _cups_smime_s cups_smime_t;
typedef ssize_t (*cups_smime_cb_t)(void *context, char *buffer, size_t bytes);

extern bool cupsSMIMEClose(cups_smime_t *smime) _CUPS_PUBLIC;
extern cups_smime_t cupsSMIMEOpen(const char *filename, const char *mode, const char *credentials, const char *key, const char *password) _CUPS_PUBLIC;
extern cups_smime_t cupsSMIMEOpenIO(void *context, cups_smime_cb_t cb, const char *mode, const char *credentials, const char *key, const char *password) _CUPS_PUBLIC;
extern ssize_t cupsSMIMERead(cups_smime_t *smime, char *buffer, size_t bytes) _CUPS_PUBLIC;
extern ssize_t cupsSMIMEWrite(cups_smime_t *smime, const char *buffer, size_t bytes) _CUPS_PUBLIC;

michaelrsweet avatar Jun 07 '23 21:06 michaelrsweet

Tracking in smime branch...

michaelrsweet avatar Jun 08 '23 14:06 michaelrsweet

RFC 8551 defines the current version of S/MIME.

RFC requirements:

  • MUST support encryption and decryption with AES-128 GCM and AES-256 GCM.
  • MUST support encryption and decryption with AES-128 CBC.
  • An S/MIME user agent MUST NOT generate asymmetric keys less than 2048 bits for use with an RSA signature algorithm.

For purposes of this implementation, only use AES-256 GCM when writing and support them all for reading - this is consistent with the "rule 2" recommendations in section 2.7.1.2 since the current IPP TRUSTNOONE specification does not provide a way for the Client to discover the supported encryption methods.

TODO: Post question on IPP mailing list proposing a Printer Description attribute to provide this information?

michaelrsweet avatar Jun 29 '23 20:06 michaelrsweet

OK, the OpenSSL CMS API doesn't allow for streaming read/write, at least not directly. Might be able to do a BIO method that handles reading/writing an IPP message with optional attached data file.

michaelrsweet avatar Jul 03 '23 21:07 michaelrsweet

OK, I've decided to defer more of this to future - I'll merge the ippAdd/CopyCredentialsString API stuff since that is immediately useful and save encoding/decoding S/MIME CMS messages for a future update.

michaelrsweet avatar Jul 04 '23 18:07 michaelrsweet