S/MIME APIs
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).
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;
Tracking in smime branch...
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?
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.
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.