Хитрость заключается в том, чтобы добавить attr в SignerInfo, а затем использовать его для подписи CMS_ContentInfo.
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <string.h>
char *lol = "roflcopter";
int main(int argc, char **argv) {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
int flags = CMS_BINARY | CMS_PARTIAL | CMS_NOSMIMECAP | CMS_DETACHED;
int ret = -1;
BIO *bio_cert_and_key = BIO_new_file("/home/umang/.isign/pair.pem", "r");
if (!bio_cert_and_key)
goto err;
X509 *scert = PEM_read_bio_X509(bio_cert_and_key, NULL, 0, NULL);
BIO_reset(bio_cert_and_key);
EVP_PKEY *skey = PEM_read_bio_PrivateKey(bio_cert_and_key, NULL, 0, NULL);
if (!scert || !skey)
goto err;
BIO *in = BIO_new_file("/tmp/test2", "r");
CMS_ContentInfo *cms = CMS_sign(NULL, NULL, NULL, in, flags);
if (!cms)
goto err;
CMS_SignerInfo *si = CMS_add1_signer(cms, scert, skey, NULL, flags);
ASN1_OBJECT *obj = OBJ_txt2obj("1.2.840.113635.100.9.1", 1);
if (!si || !obj)
goto err;
if (!CMS_signed_add1_attr_by_OBJ(si, obj, 0x4, lol, strlen(lol)) || !CMS_SignerInfo_sign(si))
goto err;
int len = i2d_CMS_ContentInfo(cms, NULL);
unsigned char *buf = malloc(len);
unsigned char *buf_2 = buf;
i2d_CMS_ContentInfo(cms, &buf);
BIO *out = BIO_new_file("/tmp/test", "wb");
if (!out)
goto err;
BIO_write(out, buf_2, len);
ret = 0;
err:
BIO_free(bio_cert_and_key);
BIO_free(in);
BIO_free(out);
CMS_ContentInfo_free(cms);
ASN1_OBJECT_free(obj);
EVP_PKEY_free(skey);
X509_free(scert);
free(buf_2);
ERR_print_errors_fp(stderr);
return ret;
}