x509_att.c revision 1.11
1/* $OpenBSD: x509_att.c,v 1.11 2014/07/11 08:44:49 jsing Exp $ */
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
61#include <openssl/asn1.h>
62#include <openssl/err.h>
63#include <openssl/evp.h>
64#include <openssl/objects.h>
65#include <openssl/stack.h>
66#include <openssl/x509.h>
67#include <openssl/x509v3.h>
68
69int
70X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
71{
72	return sk_X509_ATTRIBUTE_num(x);
73}
74
75int
76X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
77    int lastpos)
78{
79	ASN1_OBJECT *obj;
80
81	obj = OBJ_nid2obj(nid);
82	if (obj == NULL)
83		return (-2);
84	return (X509at_get_attr_by_OBJ(x, obj, lastpos));
85}
86
87int
88X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj,
89    int lastpos)
90{
91	int n;
92	X509_ATTRIBUTE *ex;
93
94	if (sk == NULL)
95		return (-1);
96	lastpos++;
97	if (lastpos < 0)
98		lastpos = 0;
99	n = sk_X509_ATTRIBUTE_num(sk);
100	for (; lastpos < n; lastpos++) {
101		ex = sk_X509_ATTRIBUTE_value(sk, lastpos);
102		if (OBJ_cmp(ex->object, obj) == 0)
103			return (lastpos);
104	}
105	return (-1);
106}
107
108X509_ATTRIBUTE *
109X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc)
110{
111	if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0)
112		return NULL;
113	else
114		return sk_X509_ATTRIBUTE_value(x, loc);
115}
116
117X509_ATTRIBUTE *
118X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc)
119{
120	X509_ATTRIBUTE *ret;
121
122	if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0)
123		return (NULL);
124	ret = sk_X509_ATTRIBUTE_delete(x, loc);
125	return (ret);
126}
127
128STACK_OF(X509_ATTRIBUTE) *
129X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, X509_ATTRIBUTE *attr)
130{
131	X509_ATTRIBUTE *new_attr = NULL;
132	STACK_OF(X509_ATTRIBUTE) *sk = NULL;
133
134	if (x == NULL) {
135		X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_PASSED_NULL_PARAMETER);
136		goto err2;
137	}
138
139	if (*x == NULL) {
140		if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL)
141			goto err;
142	} else
143		sk= *x;
144
145	if ((new_attr = X509_ATTRIBUTE_dup(attr)) == NULL)
146		goto err2;
147	if (!sk_X509_ATTRIBUTE_push(sk, new_attr))
148		goto err;
149	if (*x == NULL)
150		*x = sk;
151	return (sk);
152
153err:
154	X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_MALLOC_FAILURE);
155err2:
156	if (new_attr != NULL)
157		X509_ATTRIBUTE_free(new_attr);
158	if (sk != NULL)
159		sk_X509_ATTRIBUTE_free(sk);
160	return (NULL);
161}
162
163STACK_OF(X509_ATTRIBUTE) *
164X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, const ASN1_OBJECT *obj,
165    int type, const unsigned char *bytes, int len)
166{
167	X509_ATTRIBUTE *attr;
168	STACK_OF(X509_ATTRIBUTE) *ret;
169
170	attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len);
171	if (!attr)
172		return 0;
173	ret = X509at_add1_attr(x, attr);
174	X509_ATTRIBUTE_free(attr);
175	return ret;
176}
177
178STACK_OF(X509_ATTRIBUTE) *
179X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, int nid, int type,
180    const unsigned char *bytes, int len)
181{
182	X509_ATTRIBUTE *attr;
183	STACK_OF(X509_ATTRIBUTE) *ret;
184
185	attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len);
186	if (!attr)
187		return 0;
188	ret = X509at_add1_attr(x, attr);
189	X509_ATTRIBUTE_free(attr);
190	return ret;
191}
192
193STACK_OF(X509_ATTRIBUTE) *
194X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, const char *attrname,
195    int type, const unsigned char *bytes, int len)
196{
197	X509_ATTRIBUTE *attr;
198	STACK_OF(X509_ATTRIBUTE) *ret;
199
200	attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len);
201	if (!attr)
202		return 0;
203	ret = X509at_add1_attr(x, attr);
204	X509_ATTRIBUTE_free(attr);
205	return ret;
206}
207
208void *
209X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, ASN1_OBJECT *obj,
210    int lastpos, int type)
211{
212	int i;
213	X509_ATTRIBUTE *at;
214
215	i = X509at_get_attr_by_OBJ(x, obj, lastpos);
216	if (i == -1)
217		return NULL;
218	if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1))
219		return NULL;
220	at = X509at_get_attr(x, i);
221	if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1))
222		return NULL;
223	return X509_ATTRIBUTE_get0_data(at, 0, type, NULL);
224}
225
226X509_ATTRIBUTE *
227X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, int atrtype,
228    const void *data, int len)
229{
230	ASN1_OBJECT *obj;
231	X509_ATTRIBUTE *ret;
232
233	obj = OBJ_nid2obj(nid);
234	if (obj == NULL) {
235		X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_NID,
236		    X509_R_UNKNOWN_NID);
237		return (NULL);
238	}
239	ret = X509_ATTRIBUTE_create_by_OBJ(attr, obj, atrtype, data, len);
240	if (ret == NULL)
241		ASN1_OBJECT_free(obj);
242	return (ret);
243}
244
245X509_ATTRIBUTE *
246X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, const ASN1_OBJECT *obj,
247    int atrtype, const void *data, int len)
248{
249	X509_ATTRIBUTE *ret;
250
251	if ((attr == NULL) || (*attr == NULL)) {
252		if ((ret = X509_ATTRIBUTE_new()) == NULL) {
253			X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ,
254			    ERR_R_MALLOC_FAILURE);
255			return (NULL);
256		}
257	} else
258		ret= *attr;
259
260	if (!X509_ATTRIBUTE_set1_object(ret, obj))
261		goto err;
262	if (!X509_ATTRIBUTE_set1_data(ret, atrtype, data, len))
263		goto err;
264
265	if ((attr != NULL) && (*attr == NULL))
266		*attr = ret;
267	return (ret);
268
269err:
270	if ((attr == NULL) || (ret != *attr))
271		X509_ATTRIBUTE_free(ret);
272	return (NULL);
273}
274
275X509_ATTRIBUTE *
276X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, const char *atrname,
277    int type, const unsigned char *bytes, int len)
278{
279	ASN1_OBJECT *obj;
280	X509_ATTRIBUTE *nattr;
281
282	obj = OBJ_txt2obj(atrname, 0);
283	if (obj == NULL) {
284		X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_TXT,
285		    X509_R_INVALID_FIELD_NAME);
286		ERR_asprintf_error_data("name=%s", atrname);
287		return (NULL);
288	}
289	nattr = X509_ATTRIBUTE_create_by_OBJ(attr, obj, type, bytes, len);
290	ASN1_OBJECT_free(obj);
291	return nattr;
292}
293
294int
295X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj)
296{
297	if ((attr == NULL) || (obj == NULL))
298		return (0);
299	ASN1_OBJECT_free(attr->object);
300	attr->object = OBJ_dup(obj);
301	return (1);
302}
303
304int
305X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data,
306    int len)
307{
308	ASN1_TYPE *ttmp = NULL;
309	ASN1_STRING *stmp = NULL;
310	int atype = 0;
311
312	if (!attr)
313		return 0;
314	if (attrtype & MBSTRING_FLAG) {
315		stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype,
316		    OBJ_obj2nid(attr->object));
317		if (!stmp) {
318			X509err(X509_F_X509_ATTRIBUTE_SET1_DATA,
319			    ERR_R_ASN1_LIB);
320			return 0;
321		}
322		atype = stmp->type;
323	} else if (len != -1){
324		if (!(stmp = ASN1_STRING_type_new(attrtype)))
325			goto err;
326		if (!ASN1_STRING_set(stmp, data, len))
327			goto err;
328		atype = attrtype;
329	}
330	if (!(attr->value.set = sk_ASN1_TYPE_new_null()))
331		goto err;
332	attr->single = 0;
333	/* This is a bit naughty because the attribute should really have
334	 * at least one value but some types use and zero length SET and
335	 * require this.
336	 */
337	if (attrtype == 0) {
338		ASN1_STRING_free(stmp);
339		return 1;
340	}
341
342	if (!(ttmp = ASN1_TYPE_new()))
343		goto err;
344	if ((len == -1) && !(attrtype & MBSTRING_FLAG)) {
345		if (!ASN1_TYPE_set1(ttmp, attrtype, data))
346			goto err;
347	} else
348		ASN1_TYPE_set(ttmp, atype, stmp);
349	if (!sk_ASN1_TYPE_push(attr->value.set, ttmp))
350		goto err;
351	return 1;
352
353err:
354	ASN1_TYPE_free(ttmp);
355	ASN1_STRING_free(stmp);
356	X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_MALLOC_FAILURE);
357	return 0;
358}
359
360int
361X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr)
362{
363	if (!attr->single)
364		return sk_ASN1_TYPE_num(attr->value.set);
365	if (attr->value.single)
366		return 1;
367	return 0;
368}
369
370ASN1_OBJECT *
371X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr)
372{
373	if (attr == NULL)
374		return (NULL);
375	return (attr->object);
376}
377
378void *
379X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, int atrtype, void *data)
380{
381	ASN1_TYPE *ttmp;
382
383	ttmp = X509_ATTRIBUTE_get0_type(attr, idx);
384	if (!ttmp)
385		return NULL;
386	if (atrtype != ASN1_TYPE_get(ttmp)){
387		X509err(X509_F_X509_ATTRIBUTE_GET0_DATA, X509_R_WRONG_TYPE);
388		return NULL;
389	}
390	return ttmp->value.ptr;
391}
392
393ASN1_TYPE *
394X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx)
395{
396	if (attr == NULL)
397		return (NULL);
398	if (idx >= X509_ATTRIBUTE_count(attr))
399		return NULL;
400	if (!attr->single)
401		return sk_ASN1_TYPE_value(attr->value.set, idx);
402	else
403		return attr->value.single;
404}
405