]>
Commit | Line | Data |
---|---|---|
b1322259 RS |
1 | /* |
2 | * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. | |
b38f9f66 | 3 | * |
b1322259 RS |
4 | * Licensed under the OpenSSL license (the "License"). You may not use |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
b38f9f66 DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
11 | #include <openssl/stack.h> | |
b39fc560 | 12 | #include "internal/cryptlib.h" |
b38f9f66 DSH |
13 | #include <openssl/asn1.h> |
14 | #include <openssl/objects.h> | |
15 | #include <openssl/evp.h> | |
16 | #include <openssl/x509.h> | |
17 | #include <openssl/x509v3.h> | |
9b0a4531 | 18 | #include "x509_lcl.h" |
b38f9f66 | 19 | |
77b47b90 | 20 | int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x) |
b38f9f66 | 21 | { |
0f113f3e | 22 | return sk_X509_ATTRIBUTE_num(x); |
b38f9f66 DSH |
23 | } |
24 | ||
77b47b90 | 25 | int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, |
0f113f3e | 26 | int lastpos) |
b38f9f66 | 27 | { |
0f113f3e | 28 | ASN1_OBJECT *obj; |
b38f9f66 | 29 | |
0f113f3e MC |
30 | obj = OBJ_nid2obj(nid); |
31 | if (obj == NULL) | |
32 | return (-2); | |
33 | return (X509at_get_attr_by_OBJ(x, obj, lastpos)); | |
b38f9f66 DSH |
34 | } |
35 | ||
0f113f3e MC |
36 | int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, |
37 | ASN1_OBJECT *obj, int lastpos) | |
b38f9f66 | 38 | { |
0f113f3e MC |
39 | int n; |
40 | X509_ATTRIBUTE *ex; | |
b38f9f66 | 41 | |
0f113f3e MC |
42 | if (sk == NULL) |
43 | return (-1); | |
44 | lastpos++; | |
45 | if (lastpos < 0) | |
46 | lastpos = 0; | |
47 | n = sk_X509_ATTRIBUTE_num(sk); | |
48 | for (; lastpos < n; lastpos++) { | |
49 | ex = sk_X509_ATTRIBUTE_value(sk, lastpos); | |
50 | if (OBJ_cmp(ex->object, obj) == 0) | |
51 | return (lastpos); | |
52 | } | |
53 | return (-1); | |
b38f9f66 DSH |
54 | } |
55 | ||
77b47b90 | 56 | X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc) |
b38f9f66 | 57 | { |
0f113f3e MC |
58 | if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0) |
59 | return NULL; | |
60 | else | |
61 | return sk_X509_ATTRIBUTE_value(x, loc); | |
b38f9f66 DSH |
62 | } |
63 | ||
77b47b90 | 64 | X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) |
b38f9f66 | 65 | { |
0f113f3e | 66 | X509_ATTRIBUTE *ret; |
b38f9f66 | 67 | |
0f113f3e MC |
68 | if (x == NULL || sk_X509_ATTRIBUTE_num(x) <= loc || loc < 0) |
69 | return (NULL); | |
70 | ret = sk_X509_ATTRIBUTE_delete(x, loc); | |
71 | return (ret); | |
b38f9f66 DSH |
72 | } |
73 | ||
c7cb16a8 | 74 | STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, |
0f113f3e | 75 | X509_ATTRIBUTE *attr) |
b38f9f66 | 76 | { |
0f113f3e MC |
77 | X509_ATTRIBUTE *new_attr = NULL; |
78 | STACK_OF(X509_ATTRIBUTE) *sk = NULL; | |
b38f9f66 | 79 | |
0f113f3e MC |
80 | if (x == NULL) { |
81 | X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_PASSED_NULL_PARAMETER); | |
82 | goto err2; | |
83 | } | |
c755c5fd | 84 | |
0f113f3e MC |
85 | if (*x == NULL) { |
86 | if ((sk = sk_X509_ATTRIBUTE_new_null()) == NULL) | |
87 | goto err; | |
88 | } else | |
89 | sk = *x; | |
b38f9f66 | 90 | |
0f113f3e MC |
91 | if ((new_attr = X509_ATTRIBUTE_dup(attr)) == NULL) |
92 | goto err2; | |
93 | if (!sk_X509_ATTRIBUTE_push(sk, new_attr)) | |
94 | goto err; | |
95 | if (*x == NULL) | |
96 | *x = sk; | |
97 | return (sk); | |
98 | err: | |
99 | X509err(X509_F_X509AT_ADD1_ATTR, ERR_R_MALLOC_FAILURE); | |
100 | err2: | |
222561fe RS |
101 | X509_ATTRIBUTE_free(new_attr); |
102 | sk_X509_ATTRIBUTE_free(sk); | |
0f113f3e | 103 | return (NULL); |
b38f9f66 DSH |
104 | } |
105 | ||
0f113f3e MC |
106 | STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) |
107 | **x, const ASN1_OBJECT *obj, | |
108 | int type, | |
109 | const unsigned char *bytes, | |
110 | int len) | |
77b47b90 | 111 | { |
0f113f3e MC |
112 | X509_ATTRIBUTE *attr; |
113 | STACK_OF(X509_ATTRIBUTE) *ret; | |
114 | attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); | |
115 | if (!attr) | |
116 | return 0; | |
117 | ret = X509at_add1_attr(x, attr); | |
118 | X509_ATTRIBUTE_free(attr); | |
119 | return ret; | |
77b47b90 DSH |
120 | } |
121 | ||
0f113f3e MC |
122 | STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) |
123 | **x, int nid, int type, | |
124 | const unsigned char *bytes, | |
125 | int len) | |
77b47b90 | 126 | { |
0f113f3e MC |
127 | X509_ATTRIBUTE *attr; |
128 | STACK_OF(X509_ATTRIBUTE) *ret; | |
129 | attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); | |
130 | if (!attr) | |
131 | return 0; | |
132 | ret = X509at_add1_attr(x, attr); | |
133 | X509_ATTRIBUTE_free(attr); | |
134 | return ret; | |
77b47b90 DSH |
135 | } |
136 | ||
0f113f3e MC |
137 | STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) |
138 | **x, const char *attrname, | |
139 | int type, | |
140 | const unsigned char *bytes, | |
141 | int len) | |
77b47b90 | 142 | { |
0f113f3e MC |
143 | X509_ATTRIBUTE *attr; |
144 | STACK_OF(X509_ATTRIBUTE) *ret; | |
145 | attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len); | |
146 | if (!attr) | |
147 | return 0; | |
148 | ret = X509at_add1_attr(x, attr); | |
149 | X509_ATTRIBUTE_free(attr); | |
150 | return ret; | |
77b47b90 DSH |
151 | } |
152 | ||
4d318c79 | 153 | void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, |
0f113f3e | 154 | ASN1_OBJECT *obj, int lastpos, int type) |
4d318c79 | 155 | { |
0f113f3e MC |
156 | int i; |
157 | X509_ATTRIBUTE *at; | |
158 | i = X509at_get_attr_by_OBJ(x, obj, lastpos); | |
159 | if (i == -1) | |
160 | return NULL; | |
161 | if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1)) | |
162 | return NULL; | |
163 | at = X509at_get_attr(x, i); | |
164 | if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1)) | |
165 | return NULL; | |
166 | return X509_ATTRIBUTE_get0_data(at, 0, type, NULL); | |
4d318c79 DSH |
167 | } |
168 | ||
b38f9f66 | 169 | X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, |
0f113f3e MC |
170 | int atrtype, const void *data, |
171 | int len) | |
b38f9f66 | 172 | { |
0f113f3e MC |
173 | ASN1_OBJECT *obj; |
174 | X509_ATTRIBUTE *ret; | |
b38f9f66 | 175 | |
0f113f3e MC |
176 | obj = OBJ_nid2obj(nid); |
177 | if (obj == NULL) { | |
178 | X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_NID, X509_R_UNKNOWN_NID); | |
179 | return (NULL); | |
180 | } | |
181 | ret = X509_ATTRIBUTE_create_by_OBJ(attr, obj, atrtype, data, len); | |
182 | if (ret == NULL) | |
183 | ASN1_OBJECT_free(obj); | |
184 | return (ret); | |
b38f9f66 DSH |
185 | } |
186 | ||
187 | X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, | |
0f113f3e MC |
188 | const ASN1_OBJECT *obj, |
189 | int atrtype, const void *data, | |
190 | int len) | |
b38f9f66 | 191 | { |
0f113f3e | 192 | X509_ATTRIBUTE *ret; |
b38f9f66 | 193 | |
0f113f3e MC |
194 | if ((attr == NULL) || (*attr == NULL)) { |
195 | if ((ret = X509_ATTRIBUTE_new()) == NULL) { | |
196 | X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ, | |
197 | ERR_R_MALLOC_FAILURE); | |
198 | return (NULL); | |
199 | } | |
200 | } else | |
201 | ret = *attr; | |
b38f9f66 | 202 | |
0f113f3e MC |
203 | if (!X509_ATTRIBUTE_set1_object(ret, obj)) |
204 | goto err; | |
205 | if (!X509_ATTRIBUTE_set1_data(ret, atrtype, data, len)) | |
206 | goto err; | |
8528128b | 207 | |
0f113f3e MC |
208 | if ((attr != NULL) && (*attr == NULL)) |
209 | *attr = ret; | |
210 | return (ret); | |
211 | err: | |
212 | if ((attr == NULL) || (ret != *attr)) | |
213 | X509_ATTRIBUTE_free(ret); | |
214 | return (NULL); | |
b38f9f66 DSH |
215 | } |
216 | ||
77b47b90 | 217 | X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, |
0f113f3e MC |
218 | const char *atrname, int type, |
219 | const unsigned char *bytes, | |
220 | int len) | |
221 | { | |
222 | ASN1_OBJECT *obj; | |
223 | X509_ATTRIBUTE *nattr; | |
77b47b90 | 224 | |
0f113f3e MC |
225 | obj = OBJ_txt2obj(atrname, 0); |
226 | if (obj == NULL) { | |
227 | X509err(X509_F_X509_ATTRIBUTE_CREATE_BY_TXT, | |
228 | X509_R_INVALID_FIELD_NAME); | |
229 | ERR_add_error_data(2, "name=", atrname); | |
230 | return (NULL); | |
231 | } | |
232 | nattr = X509_ATTRIBUTE_create_by_OBJ(attr, obj, type, bytes, len); | |
233 | ASN1_OBJECT_free(obj); | |
234 | return nattr; | |
235 | } | |
77b47b90 | 236 | |
f2a253e0 | 237 | int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj) |
b38f9f66 | 238 | { |
0f113f3e MC |
239 | if ((attr == NULL) || (obj == NULL)) |
240 | return (0); | |
241 | ASN1_OBJECT_free(attr->object); | |
242 | attr->object = OBJ_dup(obj); | |
4e0e4d29 | 243 | return attr->object != NULL; |
b38f9f66 DSH |
244 | } |
245 | ||
0f113f3e MC |
246 | int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, |
247 | const void *data, int len) | |
b38f9f66 | 248 | { |
5000a6d1 | 249 | ASN1_TYPE *ttmp = NULL; |
0f113f3e MC |
250 | ASN1_STRING *stmp = NULL; |
251 | int atype = 0; | |
252 | if (!attr) | |
253 | return 0; | |
254 | if (attrtype & MBSTRING_FLAG) { | |
255 | stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype, | |
256 | OBJ_obj2nid(attr->object)); | |
257 | if (!stmp) { | |
258 | X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_ASN1_LIB); | |
259 | return 0; | |
260 | } | |
261 | atype = stmp->type; | |
262 | } else if (len != -1) { | |
75ebbd9a | 263 | if ((stmp = ASN1_STRING_type_new(attrtype)) == NULL) |
0f113f3e MC |
264 | goto err; |
265 | if (!ASN1_STRING_set(stmp, data, len)) | |
266 | goto err; | |
267 | atype = attrtype; | |
268 | } | |
0f113f3e MC |
269 | /* |
270 | * This is a bit naughty because the attribute should really have at | |
271 | * least one value but some types use and zero length SET and require | |
272 | * this. | |
273 | */ | |
5000a6d1 MC |
274 | if (attrtype == 0) { |
275 | ASN1_STRING_free(stmp); | |
0f113f3e | 276 | return 1; |
5000a6d1 | 277 | } |
75ebbd9a | 278 | if ((ttmp = ASN1_TYPE_new()) == NULL) |
0f113f3e MC |
279 | goto err; |
280 | if ((len == -1) && !(attrtype & MBSTRING_FLAG)) { | |
281 | if (!ASN1_TYPE_set1(ttmp, attrtype, data)) | |
282 | goto err; | |
5000a6d1 | 283 | } else { |
0f113f3e | 284 | ASN1_TYPE_set(ttmp, atype, stmp); |
5000a6d1 MC |
285 | stmp = NULL; |
286 | } | |
e20b5727 | 287 | if (!sk_ASN1_TYPE_push(attr->set, ttmp)) |
0f113f3e MC |
288 | goto err; |
289 | return 1; | |
290 | err: | |
291 | X509err(X509_F_X509_ATTRIBUTE_SET1_DATA, ERR_R_MALLOC_FAILURE); | |
5000a6d1 MC |
292 | ASN1_TYPE_free(ttmp); |
293 | ASN1_STRING_free(stmp); | |
0f113f3e | 294 | return 0; |
b38f9f66 DSH |
295 | } |
296 | ||
333ed02c | 297 | int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *attr) |
b38f9f66 | 298 | { |
e20b5727 DSH |
299 | if (attr == NULL) |
300 | return 0; | |
301 | return sk_ASN1_TYPE_num(attr->set); | |
b38f9f66 DSH |
302 | } |
303 | ||
c7cb16a8 | 304 | ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr) |
b38f9f66 | 305 | { |
0f113f3e MC |
306 | if (attr == NULL) |
307 | return (NULL); | |
308 | return (attr->object); | |
b38f9f66 DSH |
309 | } |
310 | ||
c7cb16a8 | 311 | void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, |
0f113f3e | 312 | int atrtype, void *data) |
b38f9f66 | 313 | { |
0f113f3e MC |
314 | ASN1_TYPE *ttmp; |
315 | ttmp = X509_ATTRIBUTE_get0_type(attr, idx); | |
316 | if (!ttmp) | |
317 | return NULL; | |
318 | if (atrtype != ASN1_TYPE_get(ttmp)) { | |
319 | X509err(X509_F_X509_ATTRIBUTE_GET0_DATA, X509_R_WRONG_TYPE); | |
320 | return NULL; | |
321 | } | |
322 | return ttmp->value.ptr; | |
b38f9f66 DSH |
323 | } |
324 | ||
c7cb16a8 | 325 | ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx) |
b38f9f66 | 326 | { |
0f113f3e | 327 | if (attr == NULL) |
0f113f3e | 328 | return NULL; |
e20b5727 | 329 | return sk_ASN1_TYPE_value(attr->set, idx); |
b38f9f66 | 330 | } |