/src/gnutls/lib/x509/attributes.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2003-2016 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2012-2016 Nikos Mavrogiannopoulos |
4 | | * Copyright (C) 2017 Red Hat, Inc. |
5 | | * |
6 | | * Author: Nikos Mavrogiannopoulos |
7 | | * |
8 | | * This file is part of GnuTLS. |
9 | | * |
10 | | * The GnuTLS is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public License |
12 | | * as published by the Free Software Foundation; either version 2.1 of |
13 | | * the License, or (at your option) any later version. |
14 | | * |
15 | | * This library is distributed in the hope that it will be useful, but |
16 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public License |
21 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
22 | | * |
23 | | */ |
24 | | |
25 | | #include "gnutls_int.h" |
26 | | |
27 | | #include <datum.h> |
28 | | #include "errors.h" |
29 | | #include <common.h> |
30 | | #include <x509.h> |
31 | | #include "x509_int.h" |
32 | | #include "attributes.h" |
33 | | |
34 | | /* Functions to parse and set the PKIX1 Attributes structure. |
35 | | */ |
36 | | |
37 | | /* Overwrite the given attribute (using the index) |
38 | | * index here starts from one. |
39 | | */ |
40 | | static int |
41 | | overwrite_attribute(asn1_node asn, const char *root, unsigned indx, |
42 | | const gnutls_datum_t * ext_data) |
43 | 0 | { |
44 | 0 | char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE]; |
45 | 0 | int result; |
46 | |
|
47 | 0 | snprintf(name, sizeof(name), "%s.?%u", root, indx); |
48 | |
|
49 | 0 | _gnutls_str_cpy(name2, sizeof(name2), name); |
50 | 0 | _gnutls_str_cat(name2, sizeof(name2), ".values.?LAST"); |
51 | |
|
52 | 0 | result = _gnutls_x509_write_value(asn, name2, ext_data); |
53 | 0 | if (result < 0) { |
54 | 0 | gnutls_assert(); |
55 | 0 | return result; |
56 | 0 | } |
57 | | |
58 | 0 | return 0; |
59 | 0 | } |
60 | | |
61 | | /* Parses an Attribute list in the asn1_struct, and searches for the |
62 | | * given OID. The index indicates the attribute value to be returned. |
63 | | * |
64 | | * If raw==0 only printable data are returned, or |
65 | | * GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE. |
66 | | * |
67 | | * asn1_attr_name must be a string in the form |
68 | | * "certificationRequestInfo.attributes" |
69 | | * |
70 | | */ |
71 | | int |
72 | | _x509_parse_attribute(asn1_node asn1_struct, |
73 | | const char *attr_name, const char *given_oid, |
74 | | unsigned indx, int raw, gnutls_datum_t * out) |
75 | 0 | { |
76 | 0 | int k1, result; |
77 | 0 | char tmpbuffer1[MAX_NAME_SIZE]; |
78 | 0 | char tmpbuffer3[MAX_NAME_SIZE]; |
79 | 0 | char value[200]; |
80 | 0 | gnutls_datum_t td; |
81 | 0 | char oid[MAX_OID_SIZE]; |
82 | 0 | int len; |
83 | |
|
84 | 0 | k1 = 0; |
85 | 0 | do { |
86 | |
|
87 | 0 | k1++; |
88 | | /* create a string like "attribute.?1" |
89 | | */ |
90 | 0 | if (attr_name[0] != 0) |
91 | 0 | snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%d", |
92 | 0 | attr_name, k1); |
93 | 0 | else |
94 | 0 | snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%d", k1); |
95 | |
|
96 | 0 | len = sizeof(value) - 1; |
97 | 0 | result = asn1_read_value(asn1_struct, tmpbuffer1, value, &len); |
98 | |
|
99 | 0 | if (result == ASN1_ELEMENT_NOT_FOUND) { |
100 | 0 | gnutls_assert(); |
101 | 0 | break; |
102 | 0 | } |
103 | | |
104 | 0 | if (result != ASN1_VALUE_NOT_FOUND) { |
105 | 0 | gnutls_assert(); |
106 | 0 | result = _gnutls_asn2err(result); |
107 | 0 | goto cleanup; |
108 | 0 | } |
109 | | |
110 | | /* Move to the attribute type and values |
111 | | */ |
112 | | /* Read the OID |
113 | | */ |
114 | 0 | _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), tmpbuffer1); |
115 | 0 | _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), ".type"); |
116 | |
|
117 | 0 | len = sizeof(oid) - 1; |
118 | 0 | result = asn1_read_value(asn1_struct, tmpbuffer3, oid, &len); |
119 | |
|
120 | 0 | if (result == ASN1_ELEMENT_NOT_FOUND) |
121 | 0 | break; |
122 | 0 | else if (result != ASN1_SUCCESS) { |
123 | 0 | gnutls_assert(); |
124 | 0 | result = _gnutls_asn2err(result); |
125 | 0 | goto cleanup; |
126 | 0 | } |
127 | | |
128 | 0 | if (strcmp(oid, given_oid) == 0) { /* Found the OID */ |
129 | | |
130 | | /* Read the Value |
131 | | */ |
132 | 0 | snprintf(tmpbuffer3, sizeof(tmpbuffer3), |
133 | 0 | "%s.values.?%u", tmpbuffer1, indx + 1); |
134 | |
|
135 | 0 | len = sizeof(value) - 1; |
136 | 0 | result = |
137 | 0 | _gnutls_x509_read_value(asn1_struct, |
138 | 0 | tmpbuffer3, &td); |
139 | |
|
140 | 0 | if (result != ASN1_SUCCESS) { |
141 | 0 | gnutls_assert(); |
142 | 0 | result = _gnutls_asn2err(result); |
143 | 0 | goto cleanup; |
144 | 0 | } |
145 | | |
146 | 0 | if (raw == 0) { |
147 | 0 | result = |
148 | 0 | _gnutls_x509_dn_to_string |
149 | 0 | (oid, td.data, td.size, out); |
150 | |
|
151 | 0 | _gnutls_free_datum(&td); |
152 | |
|
153 | 0 | if (result < 0) { |
154 | 0 | gnutls_assert(); |
155 | 0 | goto cleanup; |
156 | 0 | } |
157 | 0 | return 0; |
158 | 0 | } else { /* raw!=0 */ |
159 | 0 | out->data = td.data; |
160 | 0 | out->size = td.size; |
161 | |
|
162 | 0 | return 0; |
163 | 0 | } |
164 | 0 | } |
165 | |
|
166 | 0 | } |
167 | 0 | while (1); |
168 | | |
169 | 0 | gnutls_assert(); |
170 | |
|
171 | 0 | result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; |
172 | |
|
173 | 0 | cleanup: |
174 | 0 | return result; |
175 | 0 | } |
176 | | |
177 | | /* This function will attempt to set the requested attribute in |
178 | | * the given X509v3 certificate. |
179 | | * |
180 | | * Critical will be either 0 or 1. |
181 | | */ |
182 | | static int |
183 | | add_attribute(asn1_node asn, const char *root, const char *attribute_id, |
184 | | const gnutls_datum_t * ext_data) |
185 | 0 | { |
186 | 0 | int result; |
187 | 0 | char name[MAX_NAME_SIZE]; |
188 | |
|
189 | 0 | snprintf(name, sizeof(name), "%s", root); |
190 | | |
191 | | /* Add a new attribute in the list. |
192 | | */ |
193 | 0 | result = asn1_write_value(asn, name, "NEW", 1); |
194 | 0 | if (result != ASN1_SUCCESS) { |
195 | 0 | gnutls_assert(); |
196 | 0 | return _gnutls_asn2err(result); |
197 | 0 | } |
198 | | |
199 | 0 | snprintf(name, sizeof(name), "%s.?LAST.type", root); |
200 | |
|
201 | 0 | result = asn1_write_value(asn, name, attribute_id, 1); |
202 | 0 | if (result != ASN1_SUCCESS) { |
203 | 0 | gnutls_assert(); |
204 | 0 | return _gnutls_asn2err(result); |
205 | 0 | } |
206 | | |
207 | 0 | snprintf(name, sizeof(name), "%s.?LAST.values", root); |
208 | |
|
209 | 0 | result = asn1_write_value(asn, name, "NEW", 1); |
210 | 0 | if (result != ASN1_SUCCESS) { |
211 | 0 | gnutls_assert(); |
212 | 0 | return _gnutls_asn2err(result); |
213 | 0 | } |
214 | | |
215 | 0 | snprintf(name, sizeof(name), "%s.?LAST.values.?LAST", root); |
216 | |
|
217 | 0 | result = _gnutls_x509_write_value(asn, name, ext_data); |
218 | 0 | if (result < 0) { |
219 | 0 | gnutls_assert(); |
220 | 0 | return result; |
221 | 0 | } |
222 | | |
223 | 0 | return 0; |
224 | 0 | } |
225 | | |
226 | | int |
227 | | _x509_set_attribute(asn1_node asn, const char *root, |
228 | | const char *ext_id, const gnutls_datum_t * ext_data) |
229 | 0 | { |
230 | 0 | int result; |
231 | 0 | int k, len; |
232 | 0 | char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE]; |
233 | 0 | char extnID[MAX_OID_SIZE]; |
234 | | |
235 | | /* Find the index of the given attribute. |
236 | | */ |
237 | 0 | k = 0; |
238 | 0 | do { |
239 | 0 | k++; |
240 | |
|
241 | 0 | snprintf(name, sizeof(name), "%s.?%d", root, k); |
242 | |
|
243 | 0 | len = sizeof(extnID) - 1; |
244 | 0 | result = asn1_read_value(asn, name, extnID, &len); |
245 | | |
246 | | /* move to next |
247 | | */ |
248 | |
|
249 | 0 | if (result == ASN1_ELEMENT_NOT_FOUND) { |
250 | 0 | break; |
251 | 0 | } |
252 | | |
253 | 0 | do { |
254 | |
|
255 | 0 | _gnutls_str_cpy(name2, sizeof(name2), name); |
256 | 0 | _gnutls_str_cat(name2, sizeof(name2), ".type"); |
257 | |
|
258 | 0 | len = sizeof(extnID) - 1; |
259 | 0 | result = asn1_read_value(asn, name2, extnID, &len); |
260 | |
|
261 | 0 | if (result == ASN1_ELEMENT_NOT_FOUND) { |
262 | 0 | gnutls_assert(); |
263 | 0 | break; |
264 | 0 | } else if (result != ASN1_SUCCESS) { |
265 | 0 | gnutls_assert(); |
266 | 0 | return _gnutls_asn2err(result); |
267 | 0 | } |
268 | | |
269 | | /* Handle Extension |
270 | | */ |
271 | 0 | if (strcmp(extnID, ext_id) == 0) { |
272 | | /* attribute was found |
273 | | */ |
274 | 0 | return overwrite_attribute(asn, root, k, |
275 | 0 | ext_data); |
276 | 0 | } |
277 | |
|
278 | 0 | } |
279 | 0 | while (0); |
280 | 0 | } |
281 | 0 | while (1); |
282 | | |
283 | 0 | if (result == ASN1_ELEMENT_NOT_FOUND) { |
284 | 0 | return add_attribute(asn, root, ext_id, ext_data); |
285 | 0 | } else { |
286 | 0 | gnutls_assert(); |
287 | 0 | return _gnutls_asn2err(result); |
288 | 0 | } |
289 | | |
290 | 0 | return 0; |
291 | 0 | } |