We currenlty can't adhere to the S/MIME standards that specify that a cert can contain multiple email addresses because the only api in the s/mime libraries is: char * NSS_CMSSignerInfo_GetSignerEmailAddress() Note that NSS_CMSSignerInfo_GetSignerEmailAddress returns CERTCertificate.emailAddr, which is created by a call to lib/certdb/alg1485.c:CERT_GetCertificateEmailAddress(CERTCertificate *cert) That function seems to be looking at all the right places, but only returns one email address. The very existence of CERTCErtificate.emailAddr is questionable, since certs can have more than one. Maybe we can add a field to CERTCertificate that would contain a list of email addresses? Maybe we can have a function that computes the list on demand? What do you think?
*** Bug 124070 has been marked as a duplicate of this bug. ***
*** Bug 152984 has been marked as a duplicate of this bug. ***
It seems that CERTCErtificate.emailAddr is used as the key to the S/MIME profiles. CERT_GetCertificateEmailAddress recomputes the email address every time; it does not use CERTCErtificate.emailAddr. So I think we also need to look at how the S/MIME profiles are stored to handle the possibility that multiple email addresses correspond to the same S/MIME profile.
Unfortunately the CERTCertificate datastructure is pretty much locked in place as long as we are still mantaining binary compatibility (Unfortunately the data structure was exported when it should have been Opaque). The underlying NSS database does not handle multiple email address all that well, since there is a one-for-one index between email address and certificate Subject. We can, however provide a function which lists all the valid email addresses for a given certificate. I don't think will give you all you need to handle the many-to-many email-to-certificate semantic we want to support. Adding this function is still scheduled for NSS 3.6, P2.
Assigned the bug to Nelson.
Nelson, please investigate how much work it is to implement a function that takes a cert and an email address as arguments and returns a Boolean indicating whether the cert contains that email address. This Boolean function should meet the immediate need of the S/MIME code in the Mozilla client. It is not as general as the function Stephane requested, but avoids the whole issues of the format of the list of email addresses, whether the list should be returned or stored in CERTCertificate, and how to free the list.
Moved to NSS 3.7, priority P1.
PSM folks, NSS_CMSSignerInfo_GetSignerEmailAddress takes this argument: NSSCMSSignerInfo *sinfo Another function in that family, NSS_CMSSignerInfo_GetSigningCertificate also takes a NSSCMSSignerInfo *, and returns a CERTCertificate *. The CERTCertificate pointer returned by NSS_CMSSignerInfo_GetSigningCertificate is a new reference to the CERTCertificate, and the reference must be destroyed with a call to CERT_DestroyCertificate to avoid a leak. I propose two new functions: char * CERT_GetFirstEmailAddress(CERTCertificate * cert); and char * CERT_GetNextEmailAddress(char * prevEmailAddress); These functions will return a pointer to a UTF8 string, or NULL. The value returned by GetFirst will be passed to GetNext, and each value returned by GetNext will be passed to the next call to GetNext, until GetNext returns a NULL. The char * pointers returned point to storage that is part of the CERTCertificate's arena. The pointer will remain good as long as the caller retains a reference to the CERTCertificate. The caller must strdup (or otherwise copy) the data if he wishes to keep it after releasing the reference to the CERTCertificate. How does this sound? I'm coding it up now.
One minor correction to the proposal: instead of taking and returning char *, they'll take and return const char *. That should keep the callers from doing bad things with the data.
Nelson, Ideally we just need one function: const char *const* CERT_GetEmailAddresses(CERTCertificate *cert); or char ** CERT_GetEmailAddresses(CERTCertificate *cert, PLArenaPool *arena); I know why you proposed the CERT_GetFirstEmailAddress and CERT_GetNextEmailAddress functions -- you want to store the list of email addresses in CERTCertificate without adding a new field. They are fine by me although they look inefficient (we need a strlen call rather than a pointer increment to get the next email address) to someone who doesn't know the reason behind them.
Can email addresses be UTF8 strings?
taka, do you know what kind of encoding there can be in an email address?
Let's not get hung up on UTF8. The scheme I propose will work on any character set that does not use wide characters, and that has no zero bytes in any of the characters that might be used in an email address. That includes the following character sets, and probably others, too: UTF8, ISO-Latin-1 and its subsets, such as ASCII & IA5 would all work with this scheme.
Are you expecting addr-spec (e.g. email@example.com) only? Or, name-addr (e.g. Takayuki Tei <firstname.lastname@example.org>) ?
I was just wondering whether we need to specify the character encoding of the strings returned by the new functions Nelson proposed in comment #9.
In reply to comment 15, Taka, I expect that all the email addresses in the certificate will be addr-spec only. RFC 3280 says: When the subjectAltName extension contains an Internet mail address, the address MUST be included as an rfc822Name. The format of an rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. An addr-spec has the form "local-part@domain". Note that an addr-spec has no phrase (such as a common name) before it, has no comment (text surrounded in parentheses) after it, and is not surrounded by "<" and ">". Note that while upper and lower case letters are allowed in an RFC 822 addr-spec, no significance is attached to the case. It also says: In addition, legacy implementations exist where an RFC 822 name is embedded in the subject distinguished name as an EmailAddress attribute. The attribute value for EmailAddress is of type IA5String to permit inclusion of the character '@', which is not part of the PrintableString character set. EmailAddress attribute values are not case sensitive (e.g., "email@example.com" is the same as "FANFEEDBACK@REDSOX.COM"). IA5String is a subset of ASCII. In reply to comment 16, Wan-Teh, RFC 822 and its successor RFC 2822 both state that all the characters in the email headers (including email addresses) must be ACII characters in the range 1-127. I expect we will see some certificates with ISO-Latin-1 characters in the email addresses, but these are similar enough to ASCII for the purposes of string comparison, and for this API. BTW, to permit alternative implementations in the future, I now propose that the two functions be: const char * CERT_GetFirstEmailAddress(CERTCertificate *cert); const char * CERT_GetNextEmailAddress(CERTCertificate *cert, const char *prevEmailAddress); This permits the internal opaque implementation to use either a environment-like super-string, or an array of pointers to strings, without requiring any change to the callers. I'm waiting for feedback from Stephane's team on this proposal.
I recommend the API to do validation so that e-mail addresses are guranteed to have ASCII characters only. You shouldn't allow any characters including Latin-1, otherwise it will break things down the road.
Created attachment 103833 [details] [diff] [review] One implementation, not most efficient, but should work. If performance is a problem with this implementation, the API allows us to change it without making client's change.
Hey gang: Do we have any certs with multiple email addresses in them for testing this new code? Is so, please email them to me. Thanks.
Nelson, I'm going to create a Thawte one with both my home and work email address, and will email you.
I found a cert with 2 email addresses in it. They were the same address. The address is returned twice, once by GetFirst and again by GetNext. Patch checked in.
So this is 3.7, correct? Won't make it into Buffy then?
What NSS release will Buffy use? I've not received any request to do this in any other release than 3.7. This change adds new API functions to NSS, by which an application could access this info. We generally don't add new API functions to NSS in patch releases (such as 3.6.1). But even if we did add it to 3.6.1, would any new code be written in PSM to make use of this new feature for Buffy?
Charles, We plan to release NSS 3.7 RTM on 3/3/2003 and the earliest time Mozilla can have to the new NSS 3.7 APIs is the NSS 3.7 Beta release on 2/10/2003. Kai can pull NSS 3.7 pre-release for his development. If this is too late for you we can talk about it. Our schedule is tentative at the moment and there is some flexibility to adjust it.
There's another issue about this API that needs to be resolved, perhaps resulting in a change to the code just checked in. The old CERTCertificate->emailAddr string was downshifted. Every character in it came from a call to tolower(). Each byte of the original email address in the cert was passed to tolower, and the result was stored in the emailAddr string. So, when I implemented the new functions, I duplicated this behavior. Perhaps this is not the desired behavior. If the strings returned by the new API functions are intended for display purposes, then they should not be downshifted. OTOH, if they are only intended for comparison purposes, then perhaps downshifting is OK, although only characters less than 0x80 should be downshifted, IMO. Stephane, please help me get resolution to this ASAP.
Downshifting is the right thing to do. These email addresses may end up being displayed in the cert manager, where all email addresses for the "other people certs" tab are downshifted.