xref: /openbsd-src/lib/libcrypto/pkcs7/pk7_lib.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /* crypto/pkcs7/pk7_lib.c */
2 /* Copyright (C) 1995-1998 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 <openssl/objects.h>
62 #include <openssl/x509.h>
63 
64 long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg)
65 	{
66 	int nid;
67 	long ret;
68 
69 	nid=OBJ_obj2nid(p7->type);
70 
71 	switch (cmd)
72 		{
73 	case PKCS7_OP_SET_DETACHED_SIGNATURE:
74 		if (nid == NID_pkcs7_signed)
75 			{
76 			ret=p7->detached=(int)larg;
77 			}
78 		else
79 			{
80 			PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
81 			ret=0;
82 			}
83 		break;
84 	case PKCS7_OP_GET_DETACHED_SIGNATURE:
85 		if (nid == NID_pkcs7_signed)
86 			{
87 			ret=p7->detached;
88 			}
89 		else
90 			{
91 			PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE);
92 			ret=0;
93 			}
94 
95 		break;
96 	default:
97 		PKCS7err(PKCS7_F_PKCS7_CTRL,PKCS7_R_UNKNOWN_OPERATION);
98 		ret=0;
99 		}
100 	return(ret);
101 	}
102 
103 int PKCS7_content_new(PKCS7 *p7, int type)
104 	{
105 	PKCS7 *ret=NULL;
106 
107 	if ((ret=PKCS7_new()) == NULL) goto err;
108 	if (!PKCS7_set_type(ret,type)) goto err;
109 	if (!PKCS7_set_content(p7,ret)) goto err;
110 
111 	return(1);
112 err:
113 	if (ret != NULL) PKCS7_free(ret);
114 	return(0);
115 	}
116 
117 int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data)
118 	{
119 	int i;
120 
121 	i=OBJ_obj2nid(p7->type);
122 	switch (i)
123 		{
124 	case NID_pkcs7_signed:
125 		if (p7->d.sign->contents != NULL)
126 			PKCS7_free(p7->d.sign->contents);
127 		p7->d.sign->contents=p7_data;
128 		break;
129 	case NID_pkcs7_digest:
130 	case NID_pkcs7_data:
131 	case NID_pkcs7_enveloped:
132 	case NID_pkcs7_signedAndEnveloped:
133 	case NID_pkcs7_encrypted:
134 	default:
135 		PKCS7err(PKCS7_F_PKCS7_SET_CONTENT,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
136 		goto err;
137 		}
138 	return(1);
139 err:
140 	return(0);
141 	}
142 
143 int PKCS7_set_type(PKCS7 *p7, int type)
144 	{
145 	ASN1_OBJECT *obj;
146 
147 	PKCS7_content_free(p7);
148 	obj=OBJ_nid2obj(type); /* will not fail */
149 
150 	switch (type)
151 		{
152 	case NID_pkcs7_signed:
153 		p7->type=obj;
154 		if ((p7->d.sign=PKCS7_SIGNED_new()) == NULL)
155 			goto err;
156 		ASN1_INTEGER_set(p7->d.sign->version,1);
157 		break;
158 	case NID_pkcs7_data:
159 		p7->type=obj;
160 		if ((p7->d.data=M_ASN1_OCTET_STRING_new()) == NULL)
161 			goto err;
162 		break;
163 	case NID_pkcs7_signedAndEnveloped:
164 		p7->type=obj;
165 		if ((p7->d.signed_and_enveloped=PKCS7_SIGN_ENVELOPE_new())
166 			== NULL) goto err;
167 		ASN1_INTEGER_set(p7->d.signed_and_enveloped->version,1);
168 		break;
169 	case NID_pkcs7_enveloped:
170 		p7->type=obj;
171 		if ((p7->d.enveloped=PKCS7_ENVELOPE_new())
172 			== NULL) goto err;
173 		ASN1_INTEGER_set(p7->d.enveloped->version,0);
174 		break;
175 	case NID_pkcs7_encrypted:
176 		p7->type=obj;
177 		if ((p7->d.encrypted=PKCS7_ENCRYPT_new())
178 			== NULL) goto err;
179 		ASN1_INTEGER_set(p7->d.encrypted->version,0);
180 		break;
181 
182 	case NID_pkcs7_digest:
183 	default:
184 		PKCS7err(PKCS7_F_PKCS7_SET_TYPE,PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
185 		goto err;
186 		}
187 	return(1);
188 err:
189 	return(0);
190 	}
191 
192 int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *psi)
193 	{
194 	int i,j,nid;
195 	X509_ALGOR *alg;
196 	STACK_OF(PKCS7_SIGNER_INFO) *signer_sk;
197 	STACK_OF(X509_ALGOR) *md_sk;
198 
199 	i=OBJ_obj2nid(p7->type);
200 	switch (i)
201 		{
202 	case NID_pkcs7_signed:
203 		signer_sk=	p7->d.sign->signer_info;
204 		md_sk=		p7->d.sign->md_algs;
205 		break;
206 	case NID_pkcs7_signedAndEnveloped:
207 		signer_sk=	p7->d.signed_and_enveloped->signer_info;
208 		md_sk=		p7->d.signed_and_enveloped->md_algs;
209 		break;
210 	default:
211 		PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,PKCS7_R_WRONG_CONTENT_TYPE);
212 		return(0);
213 		}
214 
215 	nid=OBJ_obj2nid(psi->digest_alg->algorithm);
216 
217 	/* If the digest is not currently listed, add it */
218 	j=0;
219 	for (i=0; i<sk_X509_ALGOR_num(md_sk); i++)
220 		{
221 		alg=sk_X509_ALGOR_value(md_sk,i);
222 		if (OBJ_obj2nid(alg->algorithm) == nid)
223 			{
224 			j=1;
225 			break;
226 			}
227 		}
228 	if (!j) /* we need to add another algorithm */
229 		{
230 		if(!(alg=X509_ALGOR_new())
231 			|| !(alg->parameter = ASN1_TYPE_new())) {
232 			PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,ERR_R_MALLOC_FAILURE);
233 			return(0);
234 		}
235 		alg->algorithm=OBJ_nid2obj(nid);
236 		alg->parameter->type = V_ASN1_NULL;
237 		sk_X509_ALGOR_push(md_sk,alg);
238 		}
239 
240 	sk_PKCS7_SIGNER_INFO_push(signer_sk,psi);
241 	return(1);
242 	}
243 
244 int PKCS7_add_certificate(PKCS7 *p7, X509 *x509)
245 	{
246 	int i;
247 	STACK_OF(X509) **sk;
248 
249 	i=OBJ_obj2nid(p7->type);
250 	switch (i)
251 		{
252 	case NID_pkcs7_signed:
253 		sk= &(p7->d.sign->cert);
254 		break;
255 	case NID_pkcs7_signedAndEnveloped:
256 		sk= &(p7->d.signed_and_enveloped->cert);
257 		break;
258 	default:
259 		PKCS7err(PKCS7_F_PKCS7_ADD_CERTIFICATE,PKCS7_R_WRONG_CONTENT_TYPE);
260 		return(0);
261 		}
262 
263 	if (*sk == NULL)
264 		*sk=sk_X509_new_null();
265 	CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
266 	sk_X509_push(*sk,x509);
267 	return(1);
268 	}
269 
270 int PKCS7_add_crl(PKCS7 *p7, X509_CRL *crl)
271 	{
272 	int i;
273 	STACK_OF(X509_CRL) **sk;
274 
275 	i=OBJ_obj2nid(p7->type);
276 	switch (i)
277 		{
278 	case NID_pkcs7_signed:
279 		sk= &(p7->d.sign->crl);
280 		break;
281 	case NID_pkcs7_signedAndEnveloped:
282 		sk= &(p7->d.signed_and_enveloped->crl);
283 		break;
284 	default:
285 		PKCS7err(PKCS7_F_PKCS7_ADD_CRL,PKCS7_R_WRONG_CONTENT_TYPE);
286 		return(0);
287 		}
288 
289 	if (*sk == NULL)
290 		*sk=sk_X509_CRL_new_null();
291 
292 	CRYPTO_add(&crl->references,1,CRYPTO_LOCK_X509_CRL);
293 	sk_X509_CRL_push(*sk,crl);
294 	return(1);
295 	}
296 
297 int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
298 	     EVP_MD *dgst)
299 	{
300 	char is_dsa;
301 	if (pkey->type == EVP_PKEY_DSA) is_dsa = 1;
302 	else is_dsa = 0;
303 	/* We now need to add another PKCS7_SIGNER_INFO entry */
304 	ASN1_INTEGER_set(p7i->version,1);
305 	X509_NAME_set(&p7i->issuer_and_serial->issuer,
306 		X509_get_issuer_name(x509));
307 
308 	/* because ASN1_INTEGER_set is used to set a 'long' we will do
309 	 * things the ugly way. */
310 	M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial);
311 	p7i->issuer_and_serial->serial=
312 		M_ASN1_INTEGER_dup(X509_get_serialNumber(x509));
313 
314 	/* lets keep the pkey around for a while */
315 	CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
316 	p7i->pkey=pkey;
317 
318 	/* Set the algorithms */
319 	if (is_dsa) p7i->digest_alg->algorithm=OBJ_nid2obj(NID_sha1);
320 	else
321 		p7i->digest_alg->algorithm=OBJ_nid2obj(EVP_MD_type(dgst));
322 
323 	if (p7i->digest_alg->parameter != NULL)
324 		ASN1_TYPE_free(p7i->digest_alg->parameter);
325 	if ((p7i->digest_alg->parameter=ASN1_TYPE_new()) == NULL)
326 		goto err;
327 	p7i->digest_alg->parameter->type=V_ASN1_NULL;
328 
329 	p7i->digest_enc_alg->algorithm=OBJ_nid2obj(EVP_PKEY_type(pkey->type));
330 
331 	if (p7i->digest_enc_alg->parameter != NULL)
332 		ASN1_TYPE_free(p7i->digest_enc_alg->parameter);
333 	if(is_dsa) p7i->digest_enc_alg->parameter = NULL;
334 	else {
335 		if (!(p7i->digest_enc_alg->parameter=ASN1_TYPE_new()))
336 			goto err;
337 		p7i->digest_enc_alg->parameter->type=V_ASN1_NULL;
338 	}
339 
340 	return(1);
341 err:
342 	return(0);
343 	}
344 
345 PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, EVP_PKEY *pkey,
346 	     EVP_MD *dgst)
347 	{
348 	PKCS7_SIGNER_INFO *si;
349 
350 	if ((si=PKCS7_SIGNER_INFO_new()) == NULL) goto err;
351 	if (!PKCS7_SIGNER_INFO_set(si,x509,pkey,dgst)) goto err;
352 	if (!PKCS7_add_signer(p7,si)) goto err;
353 	return(si);
354 err:
355 	return(NULL);
356 	}
357 
358 STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7)
359 	{
360 	if (PKCS7_type_is_signed(p7))
361 		{
362 		return(p7->d.sign->signer_info);
363 		}
364 	else if (PKCS7_type_is_signedAndEnveloped(p7))
365 		{
366 		return(p7->d.signed_and_enveloped->signer_info);
367 		}
368 	else
369 		return(NULL);
370 	}
371 
372 PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509)
373 	{
374 	PKCS7_RECIP_INFO *ri;
375 
376 	if ((ri=PKCS7_RECIP_INFO_new()) == NULL) goto err;
377 	if (!PKCS7_RECIP_INFO_set(ri,x509)) goto err;
378 	if (!PKCS7_add_recipient_info(p7,ri)) goto err;
379 	return(ri);
380 err:
381 	return(NULL);
382 	}
383 
384 int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri)
385 	{
386 	int i;
387 	STACK_OF(PKCS7_RECIP_INFO) *sk;
388 
389 	i=OBJ_obj2nid(p7->type);
390 	switch (i)
391 		{
392 	case NID_pkcs7_signedAndEnveloped:
393 		sk=	p7->d.signed_and_enveloped->recipientinfo;
394 		break;
395 	case NID_pkcs7_enveloped:
396 		sk=	p7->d.enveloped->recipientinfo;
397 		break;
398 	default:
399 		PKCS7err(PKCS7_F_PKCS7_ADD_RECIPIENT_INFO,PKCS7_R_WRONG_CONTENT_TYPE);
400 		return(0);
401 		}
402 
403 	sk_PKCS7_RECIP_INFO_push(sk,ri);
404 	return(1);
405 	}
406 
407 int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509)
408 	{
409 	ASN1_INTEGER_set(p7i->version,0);
410 	X509_NAME_set(&p7i->issuer_and_serial->issuer,
411 		X509_get_issuer_name(x509));
412 
413 	M_ASN1_INTEGER_free(p7i->issuer_and_serial->serial);
414 	p7i->issuer_and_serial->serial=
415 		M_ASN1_INTEGER_dup(X509_get_serialNumber(x509));
416 
417 	X509_ALGOR_free(p7i->key_enc_algor);
418 	p7i->key_enc_algor=(X509_ALGOR *)ASN1_dup(i2d_X509_ALGOR,
419 		(char *(*)())d2i_X509_ALGOR,
420 		(char *)x509->cert_info->key->algor);
421 
422 	CRYPTO_add(&x509->references,1,CRYPTO_LOCK_X509);
423 	p7i->cert=x509;
424 
425 	return(1);
426 	}
427 
428 X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
429 	{
430 	if (PKCS7_type_is_signed(p7))
431 		return(X509_find_by_issuer_and_serial(p7->d.sign->cert,
432 			si->issuer_and_serial->issuer,
433 			si->issuer_and_serial->serial));
434 	else
435 		return(NULL);
436 	}
437 
438 int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher)
439 	{
440 	int i;
441 	ASN1_OBJECT *objtmp;
442 	PKCS7_ENC_CONTENT *ec;
443 
444 	i=OBJ_obj2nid(p7->type);
445 	switch (i)
446 		{
447 	case NID_pkcs7_signedAndEnveloped:
448 		ec=p7->d.signed_and_enveloped->enc_data;
449 		break;
450 	case NID_pkcs7_enveloped:
451 		ec=p7->d.enveloped->enc_data;
452 		break;
453 	default:
454 		PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_WRONG_CONTENT_TYPE);
455 		return(0);
456 		}
457 
458 	/* Check cipher OID exists and has data in it*/
459 	i = EVP_CIPHER_type(cipher);
460 	if(i == NID_undef) {
461 		PKCS7err(PKCS7_F_PKCS7_SET_CIPHER,PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
462 		return(0);
463 	}
464 	objtmp = OBJ_nid2obj(i);
465 
466 	ec->cipher = cipher;
467 	return 1;
468 	}
469 
470