2
$\begingroup$

I'm trying to setup an LDAP with user certificates. I have already learned that certificates can be stored in either the userCertificate attribute in DER format, or in userSMIMECertificate in PKCS#7 format, the latter having the advantage of being able to contain the full certificate chain, plus the S/MIME algorithms supported and/or preferred by the client.

However, I'm struggling with what variation of the PKCS#7 format has to be used. I can export certificates as p7b file which - as I understand it - is just a certificate bundle containing multiple certificates, but no further information.

The userSMIMECertificate obviously expects a (signed?) CMS message with no (or at least a negligible) message text. Is this the p7m format created by email clients? But that seems to be encrypted? How can I create the required userSMIMECertificate format?

$\endgroup$
2

3 Answers 3

1
$\begingroup$

tl;dr

The userSMIMECertificate attribute must hold a signed S/MIME message.

To create the contents for userSMIMECertificate, sign an email message with an empty message body, then remove all mail headers except for those describing the signature attachment.

The result should look similar to this (signature only):

Content-Disposition: attachment;
    filename=smime.p7s
Content-Type: application/pkcs7-signature;
    name=smime.p7s
Content-Transfer-Encoding: base64

MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIEQTCCBD0w
ggMloAMCAQICAQIwDQYJKoZIhvcNAQELBQAwgbYxGjAYBgNVBAMMEXNhdmlnbmFubyBDRVJULWky
MSUwIwYDVQQKDBxzYXZpZ25hbm8gc29mdHdhcmUgc29sdXRpb25zMR4wHAYDVQQLDBVDZXJ0aWZp
[...and so on...]
wtIEojI4gYW+wg/50/viPjxisPIPm3dEJbM+CN5gnySH9HwAAAAAAAA=

or like this (multipart message):

MIME-Version: 1.0
Content-Type: multipart/signed;
    protocol="application/x-pkcs7-signature";
    micalg=SHA1;
    boundary="----=_NextPart_000_003C_01D7312D.9474A240"

This is a multipart message in MIME format.

------=_NextPart_000_003C_01D7312D.9474A240
Content-Type: text/plain;
    charset="us-ascii"
Content-Transfer-Encoding: 7bit

This contents part may be empty or not and will be ignored.

------=_NextPart_000_003C_01D7312D.9474A240
Content-Disposition: attachment;
    filename=smime.p7s
Content-Type: application/pkcs7-signature;
    name=smime.p7s
Content-Transfer-Encoding: base64

MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCCDUw
ggQDMIIC66ADAgECAgRK+N2BMA0GCSqGSIb3DQEBCwUAMIHAMSMwIQYDVQQDDBpzYXZpZ25hbm8g
[...]
E3toHxuZzFrZMnMobwmt1nbAwNodpSsAAAAAAAA=

------=_NextPart_000_003C_01D7312D.9474A240--

This format can be created manually by signing an empty message using an email client, then saving that email in text format and removing the unwanted headers in an editor.

To create this format with openssl, use:

openssl smime -sign -in empty.txt -text -out userSMIMEcertificate.txt -signer mycert.pem -certfile intermediatecerts.pem 

where mycert.pem is the signer's private certificate including its key and intermediatecerts.pem are any additional certificates that should be included. Add -inkey mykey.pem if the key is separate rather than included in the private certificate.

Note that, in order to sign the message, the certificate owner's private key is required.


Background Details

Format

The userSMIMECertificate is designed to hold a signed message that is signed using the user's email certificate. Additionally, it can and it should also contain the other certificates needed for chaining and verifying the user certificate. It's also designed to provide details about the encryption algorithms which are supported and preferred by the email client.

The userSMIMECertificate LDAP attribute is defined in RFC 2798: Definition of the inetOrgPerson LDAP Object Class as

A PKCS#7 [RFC2315] SignedData, where the content that is signed is
ignored by consumers of userSMIMECertificate values.

The format is based on RFC 2315: PKCS #7: Cryptographic Message Syntax. I find this RFC hard to understand, but fortunately, there is another document RFC 4134: Examples of S/MIME Messages that exhibits an example in chapter 4.9 S/MIME application/pkcs7-mime Signed Message.

As we can see there, it is an S/MIME signed email as created by any email client when sending a signed (but not encrypted) email.

According to this, it's not even necessary to remove any headers, but I recommend it for improved compatibility.

Purpose

In a quote from an original discussion with the creators of the userSMIMECertificate LDAP attribute, one of the authors explains:

Now we come to the question of why we felt we needed a new directory attribute for S/MIME certificates. I was told by our directory engineers that the existing userCertificate attribute was defined as a single raw certificate. That leaves no place to store the other certificates needed for chaining, and no place to store the algorithm capabilities. We had an existing package available to us that could contain both the certificates and the capabilities. That package is an S/MIME signed message.

The format of the userSMIMECertificate attribute is an S/MIME signed message with a zero length body. It contains the user's entire certificate chain and the signed attribute that describes their algorithm capabilities.

There is also a draft about the format to publish the data in userSMIMECertificate that provides some insight, but it has expired in 2001, and there doesn't seem to be successor to it.

Practical Notes

Weak Support

Most email clients seem not to understand a userSMIMECertificate that holds a PKCS#7 signed message. They do understand DER encoded certificates in this attribute. I'm planning to create a compatibility table but haven't yet.

Removed Headers

My above recommendation to remove all headers so only the signature is left is made because I have otherwise experienced problems with some clients, but I don't remember which. The actual definition does not require such modifications.

Algorithm Capabilities

One of the ideas for userSMIMECertificate was that the PKCS#7 data can include the owner's encryption capabilities (i.e. which ciphers they support). That way the encrypting client can select the best encryption cipher supported by both the sender and recipient of the email.

However, in extensive testing I've learned that in practice, only some (older) email clients provide such capabilities. My guess is that this feature has become obsolete by the fact that nowadays users are not confined to using only one email client all the time. Therefore, including one client's capabilities would be useless at best and might even lead to problems with the other client(s).

$\endgroup$
1
  • 1
    $\begingroup$ Note for those who find this answer when Googling: the openssl command to extract the certificate from such an attribute is: openssl pkcs7 -text -print_certs -noout -inform DER < binary_data.bin $\endgroup$ Commented Oct 5, 2023 at 14:46
1
$\begingroup$

Odd. I tried asking+posting on Cryptography first which then said my issue was out of scope. So moved to stackexchange which then also said out of scope. In any case a month or so of work with others (c programming, rev eng w/ Ghidra, pcaps) on this issue led to what I finally shared on doc.windows.com https://docs.microsoft.com/en-us/answers/questions/372996/working-sample-of-ldap-usersmimecertificate-attrib.html . So for those struggling with the same question I hope this helps and am happy to re-post full text here.

$\endgroup$
1
  • $\begingroup$ Please include at least an abstract of your findings in your answer. The other page may go down one day for some reason. $\endgroup$
    – not2savvy
    Commented Jun 8, 2021 at 11:58
0
$\begingroup$

It is PKCS7 signed message. In .Net you can use SignedCMS object

...
using System.Security.Cryptography.Pkcs;
...

var ctx = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain);
var userPrincipal  = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(ctx, System.DirectoryServices.AccountManagement.IdentityType.SamAccountName, "...account...");
var adObject= userPrincipal.GetUnderlyingObject() as System.DirectoryServices.DirectoryEntry;


var sm = adObject.Properties["userSMIMECertificate"] as byte[];
var sCMS = new SignedCms();
sCMS.Decode(smc);

ContentType is of type 1.2.840.113549.1.7.1 ( "PKCS 7 Data" ).

In my case it was not empty but contained 45 6d 70 74 79 20 42 6f 64 79

"Empty Body"

If you only need the certificates of this object, you can use the import function of the X509Certificate2Collection


var col = new System.Security.Cryptography.X509Certificates.X509Certificate2Collection();
col.Import((byte[])smc);

Creating this userSMIMECertificate object has one issue : you need access to the private keys. So it will be the user itself, or a smartcard management system (which has the card when issuing), who can create the object.

It is not necessary to use "userSMIMECertificate" , but only use "userCertificate". The latter is enterprise manageable, and using the two can give conflicts when different. It also depends on the client which one is used first.

$\endgroup$
5
  • $\begingroup$ Thanks for your additional information. However, I've never come across a recommendation not to use userSMIMECertificate. Can you elaborate on this and provide a source for your quote? My findings are that userSMIMECertificate is preferred because it is able to provide the certificate chain, while userCertificate can hold only one certificate. $\endgroup$
    – not2savvy
    Commented Jan 21, 2019 at 9:51
  • $\begingroup$ Moreover, the p7m format in userSMIMECertificate can hold information about the client's supported and preferred encryption algorithms which userCertificate cannot provide. $\endgroup$
    – not2savvy
    Commented Jan 21, 2019 at 9:56
  • $\begingroup$ userSMIMECertificate will be used first, if available. $\endgroup$ Commented Jan 21, 2019 at 13:16
  • $\begingroup$ You are contradicting your own answer, aren't you? If so, please update your answer. $\endgroup$
    – not2savvy
    Commented Jan 22, 2019 at 12:52
  • $\begingroup$ some of the answer was gone. From an "advanced user" perspective, userSMimeCertificate is usefull, but from the enterprise managed perspective, ICT cannot (technically, yes with key archival, but that should not be done) sign or manage the users sMimeCertificate, only they can maintain userCertificate. So Microsoft also has an option to disable publish to userSmimeCeriticate in group policy.. $\endgroup$ Commented Jan 22, 2019 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.