1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation.  Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above.  If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL.  If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34#include "cmslocal.h"
35
36#include "cert.h"
37#include "secitem.h"
38#include "secoid.h"
39
40#include <security_asn1/secasn1.h>
41#include <security_asn1/secerr.h>
42#include <Security/SecIdentity.h>
43
44static int
45nss_cms_recipients_traverse(SecCmsRecipientInfoRef *recipientinfos, SecCmsRecipient **recipient_list)
46{
47    int count = 0;
48    int rlindex = 0;
49    int i, j;
50    SecCmsRecipient *rle;
51    SecCmsRecipientInfoRef ri;
52    SecCmsRecipientEncryptedKey *rek;
53
54    for (i = 0; recipientinfos[i] != NULL; i++) {
55	ri = recipientinfos[i];
56	switch (ri->recipientInfoType) {
57	case SecCmsRecipientInfoIDKeyTrans:
58	    if (recipient_list) {
59		/* alloc one & fill it out */
60		rle = (SecCmsRecipient *)PORT_ZAlloc(sizeof(SecCmsRecipient));
61		if (rle == NULL)
62		    return -1;
63
64		rle->riIndex = i;
65		rle->subIndex = -1;
66		switch (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType) {
67		case SecCmsRecipientIDIssuerSN:
68		    rle->kind = RLIssuerSN;
69		    rle->id.issuerAndSN = ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN;
70		    break;
71		case SecCmsRecipientIDSubjectKeyID:
72		    rle->kind = RLSubjKeyID;
73		    rle->id.subjectKeyID = ri->ri.keyTransRecipientInfo.recipientIdentifier.id.subjectKeyID;
74		    break;
75		}
76		recipient_list[rlindex++] = rle;
77	    } else {
78		count++;
79	    }
80	    break;
81	case SecCmsRecipientInfoIDKeyAgree:
82	    if (ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys == NULL)
83		break;
84	    for (j=0; ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[j] != NULL; j++) {
85		if (recipient_list) {
86		    rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[j];
87		    /* alloc one & fill it out */
88		    rle = (SecCmsRecipient *)PORT_ZAlloc(sizeof(SecCmsRecipient));
89		    if (rle == NULL)
90			return -1;
91
92		    rle->riIndex = i;
93		    rle->subIndex = j;
94		    switch (rek->recipientIdentifier.identifierType) {
95		    case SecCmsKeyAgreeRecipientIDIssuerSN:
96			rle->kind = RLIssuerSN;
97			rle->id.issuerAndSN = rek->recipientIdentifier.id.issuerAndSN;
98			break;
99		    case SecCmsKeyAgreeRecipientIDRKeyID:
100			rle->kind = RLSubjKeyID;
101			rle->id.subjectKeyID = rek->recipientIdentifier.id.recipientKeyIdentifier.subjectKeyIdentifier;
102			break;
103		    }
104		    recipient_list[rlindex++] = rle;
105		} else {
106		    count++;
107		}
108	    }
109	    break;
110	case SecCmsRecipientInfoIDKEK:
111	    /* KEK is not implemented */
112	    break;
113	}
114    }
115    /* if we have a recipient list, we return on success (-1, above, on failure) */
116    /* otherwise, we return the count. */
117    if (recipient_list) {
118	recipient_list[rlindex] = NULL;
119	return 0;
120    } else {
121	return count;
122    }
123}
124
125SecCmsRecipient **
126nss_cms_recipient_list_create(SecCmsRecipientInfoRef *recipientinfos)
127{
128    int count, rv;
129    SecCmsRecipient **recipient_list;
130
131    /* count the number of recipient identifiers */
132    count = nss_cms_recipients_traverse(recipientinfos, NULL);
133    if (count <= 0) {
134	/* no recipients? */
135	PORT_SetError(SEC_ERROR_BAD_DATA);
136#if 0
137	PORT_SetErrorString("Cannot find recipient data in envelope.");
138#endif
139	return NULL;
140    }
141
142    /* allocate an array of pointers */
143    recipient_list = (SecCmsRecipient **)
144		    PORT_ZAlloc((count + 1) * sizeof(SecCmsRecipient *));
145    if (recipient_list == NULL)
146	return NULL;
147
148    /* now fill in the recipient_list */
149    rv = nss_cms_recipients_traverse(recipientinfos, recipient_list);
150    if (rv < 0) {
151	nss_cms_recipient_list_destroy(recipient_list);
152	return NULL;
153    }
154    return recipient_list;
155}
156
157void
158nss_cms_recipient_list_destroy(SecCmsRecipient **recipient_list)
159{
160    int i;
161    SecCmsRecipient *recipient;
162
163    for (i=0; recipient_list[i] != NULL; i++) {
164	recipient = recipient_list[i];
165	if (recipient->cert)
166	    CFRelease(recipient->cert);
167	if (recipient->privkey)
168	    CFRelease(recipient->privkey);
169#if 0
170	// @@@ Eliminate slot stuff.
171	if (recipient->slot)
172	    PK11_FreeSlot(recipient->slot);
173#endif
174	PORT_Free(recipient);
175    }
176    PORT_Free(recipient_list);
177}
178
179SecCmsRecipientEncryptedKey *
180SecCmsRecipientEncryptedKeyCreate(PLArenaPool *poolp)
181{
182    return (SecCmsRecipientEncryptedKey *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientEncryptedKey));
183}
184
185
186int
187nss_cms_FindCertAndKeyByRecipientList(SecCmsRecipient **recipient_list, void *wincx)
188{
189    SecCmsRecipient *recipient = NULL;
190    SecCertificateRef cert = NULL;
191    SecPrivateKeyRef privKey = NULL;
192    SecIdentityRef identity = NULL;
193    CFTypeRef keychainOrArray = NULL; // @@@ The caller should be able to pass this in somehow.
194    int index;
195
196    for (index = 0; recipient_list[index] != NULL; ++index)
197    {
198	recipient = recipient_list[index];
199
200	switch (recipient->kind)
201	{
202	case RLIssuerSN:
203	    identity = CERT_FindIdentityByIssuerAndSN(keychainOrArray, recipient->id.issuerAndSN);
204	    break;
205	case RLSubjKeyID:
206	    identity = CERT_FindIdentityBySubjectKeyID(keychainOrArray, recipient->id.subjectKeyID);
207	    break;
208	}
209
210	if (identity)
211	    break;
212    }
213
214    if (!recipient)
215	goto loser;
216
217    if (SecIdentityCopyCertificate(identity, &cert))
218	goto loser;
219    if (SecIdentityCopyPrivateKey(identity, &privKey))
220	goto loser;
221    CFRelease(identity);
222
223    recipient->cert = cert;
224    recipient->privkey = privKey;
225
226    return index;
227
228loser:
229    if (identity)
230	CFRelease(identity);
231    if (cert)
232	CFRelease(cert);
233    if (privKey)
234	CFRelease(privKey);
235
236    return -1;
237}
238