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/*
35 * CMS digestedData methods.
36 */
37
38#include <Security/SecCmsDigestedData.h>
39
40#include <Security/SecCmsContentInfo.h>
41#include <Security/SecCmsDigestContext.h>
42
43#include "cmslocal.h"
44
45#include "SecAsn1Item.h"
46#include "secoid.h"
47
48#include <security_asn1/secasn1.h>
49#include <security_asn1/secerr.h>
50#include <security_asn1/secport.h>
51
52/*
53 * SecCmsDigestedDataCreate - create a digestedData object (presumably for encoding)
54 *
55 * version will be set by SecCmsDigestedDataEncodeBeforeStart
56 * digestAlg is passed as parameter
57 * contentInfo must be filled by the user
58 * digest will be calculated while encoding
59 */
60SecCmsDigestedDataRef
61SecCmsDigestedDataCreate(SecCmsMessageRef cmsg, SECAlgorithmID *digestalg)
62{
63    void *mark;
64    SecCmsDigestedDataRef digd;
65    PLArenaPool *poolp;
66
67    poolp = cmsg->poolp;
68
69    mark = PORT_ArenaMark(poolp);
70
71    digd = (SecCmsDigestedDataRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsDigestedData));
72    if (digd == NULL)
73	goto loser;
74
75    digd->contentInfo.cmsg = cmsg;
76
77    if (SECOID_CopyAlgorithmID (poolp, &(digd->digestAlg), digestalg) != SECSuccess)
78	goto loser;
79
80    PORT_ArenaUnmark(poolp, mark);
81    return digd;
82
83loser:
84    PORT_ArenaRelease(poolp, mark);
85    return NULL;
86}
87
88/*
89 * SecCmsDigestedDataDestroy - destroy a digestedData object
90 */
91void
92SecCmsDigestedDataDestroy(SecCmsDigestedDataRef digd)
93{
94    /* everything's in a pool, so don't worry about the storage */
95    SecCmsContentInfoDestroy(&(digd->contentInfo));
96    return;
97}
98
99/*
100 * SecCmsDigestedDataGetContentInfo - return pointer to digestedData object's contentInfo
101 */
102SecCmsContentInfoRef
103SecCmsDigestedDataGetContentInfo(SecCmsDigestedDataRef digd)
104{
105    return &(digd->contentInfo);
106}
107
108/*
109 * SecCmsDigestedDataEncodeBeforeStart - do all the necessary things to a DigestedData
110 *     before encoding begins.
111 *
112 * In particular:
113 *  - set the right version number. The contentInfo's content type must be set up already.
114 */
115OSStatus
116SecCmsDigestedDataEncodeBeforeStart(SecCmsDigestedDataRef digd)
117{
118    unsigned long version;
119    SecAsn1Item * dummy;
120
121    version = SEC_CMS_DIGESTED_DATA_VERSION_DATA;
122    if (SecCmsContentInfoGetContentTypeTag(&(digd->contentInfo)) != SEC_OID_PKCS7_DATA)
123	version = SEC_CMS_DIGESTED_DATA_VERSION_ENCAP;
124
125    dummy = SEC_ASN1EncodeInteger(digd->contentInfo.cmsg->poolp, &(digd->version), version);
126    return (dummy == NULL) ? SECFailure : SECSuccess;
127}
128
129/*
130 * SecCmsDigestedDataEncodeBeforeData - do all the necessary things to a DigestedData
131 *     before the encapsulated data is passed through the encoder.
132 *
133 * In detail:
134 *  - set up the digests if necessary
135 */
136OSStatus
137SecCmsDigestedDataEncodeBeforeData(SecCmsDigestedDataRef digd)
138{
139    /* set up the digests */
140    if (digd->digestAlg.algorithm.Length != 0 && digd->digest.Length == 0) {
141	/* if digest is already there, do nothing */
142	digd->contentInfo.digcx = SecCmsDigestContextStartSingle(&(digd->digestAlg));
143	if (digd->contentInfo.digcx == NULL)
144	    return SECFailure;
145    }
146    return SECSuccess;
147}
148
149/*
150 * SecCmsDigestedDataEncodeAfterData - do all the necessary things to a DigestedData
151 *     after all the encapsulated data was passed through the encoder.
152 *
153 * In detail:
154 *  - finish the digests
155 */
156OSStatus
157SecCmsDigestedDataEncodeAfterData(SecCmsDigestedDataRef digd)
158{
159    OSStatus rv = SECSuccess;
160    /* did we have digest calculation going on? */
161    if (digd->contentInfo.digcx) {
162	SecAsn1Item data;
163	rv = SecCmsDigestContextFinishSingle(digd->contentInfo.digcx, &data);
164	if (rv == SECSuccess)
165	    rv = SECITEM_CopyItem(digd->contentInfo.cmsg->poolp, &(digd->digest), &data);
166	if (rv == SECSuccess)
167	    SecCmsDigestContextDestroy(digd->contentInfo.digcx);
168	digd->contentInfo.digcx = NULL;
169    }
170
171    return rv;
172}
173
174/*
175 * SecCmsDigestedDataDecodeBeforeData - do all the necessary things to a DigestedData
176 *     before the encapsulated data is passed through the encoder.
177 *
178 * In detail:
179 *  - set up the digests if necessary
180 */
181OSStatus
182SecCmsDigestedDataDecodeBeforeData(SecCmsDigestedDataRef digd)
183{
184    /* is there a digest algorithm yet? */
185    if (digd->digestAlg.algorithm.Length == 0)
186	return SECFailure;
187
188    digd->contentInfo.digcx = SecCmsDigestContextStartSingle(&(digd->digestAlg));
189    if (digd->contentInfo.digcx == NULL)
190	return SECFailure;
191
192    return SECSuccess;
193}
194
195/*
196 * SecCmsDigestedDataDecodeAfterData - do all the necessary things to a DigestedData
197 *     after all the encapsulated data was passed through the encoder.
198 *
199 * In detail:
200 *  - finish the digests
201 */
202OSStatus
203SecCmsDigestedDataDecodeAfterData(SecCmsDigestedDataRef digd)
204{
205    OSStatus rv = SECSuccess;
206    /* did we have digest calculation going on? */
207    if (digd->contentInfo.digcx) {
208	SecAsn1Item data;
209	rv = SecCmsDigestContextFinishSingle(digd->contentInfo.digcx, &data);
210	if (rv == SECSuccess)
211	    rv = SECITEM_CopyItem(digd->contentInfo.cmsg->poolp, &(digd->digest), &data);
212	if (rv == SECSuccess)
213	    SecCmsDigestContextDestroy(digd->contentInfo.digcx);
214	digd->contentInfo.digcx = NULL;
215    }
216
217    return rv;
218}
219
220/*
221 * SecCmsDigestedDataDecodeAfterEnd - finalize a digestedData.
222 *
223 * In detail:
224 *  - check the digests for equality
225 */
226OSStatus
227SecCmsDigestedDataDecodeAfterEnd(SecCmsDigestedDataRef digd)
228{
229    /* did we have digest calculation going on? */
230    if (digd->cdigest.Length != 0) {
231	/* XXX comparision btw digest & cdigest */
232	/* XXX set status */
233	/* TODO!!!! */
234    }
235
236    return SECSuccess;
237}
238