This commit was generated by cvs2svn to track changes on a CVS vendor
[openssl.git] / crypto / pkcs7 / pk7_lib.c
1 /* crypto/pkcs7/pk7_lib.c */
2 /* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60 #include "cryptlib.h"
61 #include "objects.h"
62 #include "x509.h"
63
64 long PKCS7_ctrl(p7,cmd,larg,parg)
65 PKCS7 *p7;
66 int cmd;
67 long larg;
68 char *parg;
69         {
70         int nid;
71         long ret;
72
73         nid=OBJ_obj2nid(p7->type);
74
75         switch (cmd)
76                 {
77         case PKCS7_OP_SET_DETACHED_SIGNATURE:
78                 if (nid == NID_pkcs7_signed)
79                         {
80                         ret=p7->detached=(int)larg;
81                         }
82                 else
83                         {
84                         PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
85                         ret=0;
86                         }
87                 break;
88         case PKCS7_OP_GET_DETACHED_SIGNATURE:
89                 if (nid == NID_pkcs7_signed)
90                         {
91                         ret=p7->detached;
92                         }
93                 else
94                         {
95                         PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
96                         ret=0;
97                         }
98                         
99                 break;
100         default:
101                 abort();
102                 }
103         return(ret);
104         }
105
106 int PKCS7_content_new(p7,type)
107 PKCS7 *p7;
108 int type;
109         {
110         PKCS7 *ret=NULL;
111
112         if ((ret=PKCS7_new()) == NULL) goto err;
113         if (!PKCS7_set_type(ret,type)) goto err;
114         if (!PKCS7_set_content(p7,ret)) goto err;
115
116         return(1);
117 err:
118         if (ret != NULL) PKCS7_free(ret);
119         return(0);
120         }
121
122 int PKCS7_set_content(p7,p7_data)
123 PKCS7 *p7;
124 PKCS7 *p7_data;
125         {
126         int i;
127
128         i=OBJ_obj2nid(p7->type);
129         switch (i)
130                 {
131         case NID_pkcs7_signed:
132                 if (p7->d.sign->contents != NULL)
133                         PKCS7_content_free(p7->d.sign->contents);
134                 p7->d.sign->contents=p7_data;
135                 break;
136         case NID_pkcs7_digest:
137         case NID_pkcs7_data:
138         case NID_pkcs7_enveloped:
139         case NID_pkcs7_signedAndEnveloped:
140         case NID_pkcs7_encrypted:
141         default:
142                 PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
143                 goto err;
144                 }
145         return(1);
146 err:
147         return(0);
148         }
149
150 int PKCS7_set_type(p7,type)
151 PKCS7 *p7;
152 int type;
153         {
154         ASN1_OBJECT *obj;
155
156         PKCS7_content_free(p7);
157         obj=OBJ_nid2obj(type); /* will not fail */
158
159         switch (type)
160                 {
161         case NID_pkcs7_signed:
162                 p7->type=obj;
163                 if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL)
164                         goto err;
165                 ASN1_INTEGER_set(p7->d.sign->version,1);
166                 break;
167         case NID_pkcs7_data:
168                 p7->type=obj;
169                 if ((p7->d.data=ASN1_OCTET_STRING_new()) == NULL)
170                         goto err;
171                 break;
172         case NID_pkcs7_digest:
173         case NID_pkcs7_enveloped:
174         case NID_pkcs7_signedAndEnveloped:
175         case NID_pkcs7_encrypted:
176         default:
177                 PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
178                 goto err;
179                 }
180         return(1);
181 err:
182         return(0);
183         }
184
185 int PKCS7_add_signer(p7,psi)
186 PKCS7 *p7;
187 PKCS7_SIGNER_INFO *psi;
188         {
189         int i,j,nid;
190         X509_ALGOR *alg;
191         PKCS7_SIGNED *p7s;
192
193         i=OBJ_obj2nid(p7->type);
194         if (i != NID_pkcs7_signed)
195                 {
196                 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE);
197                 return(0);
198                 }
199
200         p7s=p7->d.sign;
201
202         nid=OBJ_obj2nid(psi->digest_alg->algorithm);
203
204         /* If the digest is not currently listed, add it */
205         j=0;
206         for (i=0; i<sk_num(p7s->md_algs); i++)
207                 {
208                 alg=(X509_ALGOR *)sk_value(p7s->md_algs,i);
209                 if (OBJ_obj2nid(alg->algorithm) == nid)
210                         {
211                         j=1;
212                         break;
213                         }
214                 }
215         if (!j) /* we need to add another algorithm */
216                 {
217                 alg=X509_ALGOR_new();
218                 alg->algorithm=OBJ_nid2obj(nid);
219                 sk_push(p7s->md_algs,(char *)alg);
220                 }
221
222         sk_push(p7s->signer_info,(char *)psi);
223         return(1);
224         }
225
226 int PKCS7_add_certificate(p7,x509)
227 PKCS7 *p7;
228 X509 *x509;
229         {
230         int i;
231
232         i=OBJ_obj2nid(p7->type);
233         if (i != NID_pkcs7_signed)
234                 {
235                 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE);
236                 return(0);
237                 }
238
239         if (p7->d.sign->cert == NULL)
240                 p7->d.sign->cert=sk_new_null();
241         CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
242         sk_push(p7->d.sign->cert,(char *)x509);
243         return(1);
244         }
245
246 int PKCS7_add_crl(p7,crl)
247 PKCS7 *p7;
248 X509_CRL *crl;
249         {
250         int i;
251         i=OBJ_obj2nid(p7->type);
252         if (i != NID_pkcs7_signed)
253                 {
254                 PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE);
255                 return(0);
256                 }
257
258         if (p7->d.sign->crl == NULL)
259                 p7->d.sign->crl=sk_new_null();
260
261         CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL);
262         sk_push(p7->d.sign->crl,(char *)crl);
263         return(1);
264         }
265
266 int PKCS7_SIGNER_INFO_set(p7i,x509,pkey,dgst)
267 PKCS7_SIGNER_INFO *p7i;
268 X509 *x509;
269 EVP_PKEY *pkey;
270 EVP_MD *dgst;
271         {
272         /* We now need to add another PKCS7_SIGNER_INFO entry */
273         ASN1_INTEGER_set(p7i->version,1);
274         X509_NAME_set(&p7i->issuer_and_serial->issuer,
275                 X509_get_issuer_name(x509));
276
277         /* because ASN1_INTEGER_set is used to set a 'long' we will do
278          * things the ugly way. */
279         ASN1_INTEGER_free(p7i->issuer_and_serial->serial);
280         p7i->issuer_and_serial->serial=
281                 ASN1_INTEGER_dup(X509_get_serialNumber(x509));
282
283         /* lets keep the pkey around for a while */
284         CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
285         p7i->pkey=pkey;
286
287         /* Set the algorithms */
288         p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst));
289         p7i->digest_enc_alg->algorithm=OBJ_nid2obj(EVP_MD_pkey_type(dgst));
290
291 #if 1
292         if (p7i->digest_enc_alg->parameter != NULL)
293                 ASN1_TYPE_free(p7i->digest_enc_alg->parameter);
294         if ((p7i->digest_enc_alg->parameter=ASN1_TYPE_new()) == NULL)
295                 goto err;
296         p7i->digest_enc_alg->parameter->type=V_ASN1_NULL;
297 #endif
298
299
300         return(1);
301 err:
302         return(0);
303         }
304
305 PKCS7_SIGNER_INFO *PKCS7_add_signature(p7,x509,pkey,dgst)
306 PKCS7 *p7;
307 X509 *x509;
308 EVP_PKEY *pkey;
309 EVP_MD *dgst;
310         {
311         PKCS7_SIGNER_INFO *si;
312
313         if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err;
314         if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err;
315         if (!PKCS7_add_signer(p7,si)) goto err;
316         return(si);
317 err:
318         return(NULL);
319         }
320
321 STACK *PKCS7_get_signer_info(p7)
322 PKCS7 *p7;
323         {
324         if (PKCS7_type_is_signed(p7))
325                 {
326                 return(p7->d.sign->signer_info);
327                 }
328         else
329                 return(NULL);
330         }
331
332 X509 *PKCS7_cert_from_signer_info(p7,si)
333 PKCS7 *p7;
334 PKCS7_SIGNER_INFO *si;
335         {
336         if (PKCS7_type_is_signed(p7))
337                 return(X509_find_by_issuer_and_serial(p7->d.sign->cert,
338                         si->issuer_and_serial->issuer,
339                         si->issuer_and_serial->serial));
340         else
341                 return(NULL);
342         }
343