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
overwrite_attribute(ASN1_TYPE asn,const char * root,unsigned indx,const gnutls_datum_t * ext_data)41 overwrite_attribute(ASN1_TYPE asn, const char *root, unsigned indx,
42 const gnutls_datum_t * ext_data)
43 {
44 char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
45 int result;
46
47 snprintf(name, sizeof(name), "%s.?%u", root, indx);
48
49 _gnutls_str_cpy(name2, sizeof(name2), name);
50 _gnutls_str_cat(name2, sizeof(name2), ".values.?LAST");
51
52 result = _gnutls_x509_write_value(asn, name2, ext_data);
53 if (result < 0) {
54 gnutls_assert();
55 return result;
56 }
57
58
59 return 0;
60 }
61
62 /* Parses an Attribute list in the asn1_struct, and searches for the
63 * given OID. The index indicates the attribute value to be returned.
64 *
65 * If raw==0 only printable data are returned, or
66 * GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE.
67 *
68 * asn1_attr_name must be a string in the form
69 * "certificationRequestInfo.attributes"
70 *
71 */
72 int
_x509_parse_attribute(ASN1_TYPE asn1_struct,const char * attr_name,const char * given_oid,unsigned indx,int raw,gnutls_datum_t * out)73 _x509_parse_attribute(ASN1_TYPE asn1_struct,
74 const char *attr_name, const char *given_oid, unsigned indx,
75 int raw, gnutls_datum_t * out)
76 {
77 int k1, result;
78 char tmpbuffer1[MAX_NAME_SIZE];
79 char tmpbuffer3[MAX_NAME_SIZE];
80 char value[200];
81 gnutls_datum_t td;
82 char oid[MAX_OID_SIZE];
83 int len;
84
85 k1 = 0;
86 do {
87
88 k1++;
89 /* create a string like "attribute.?1"
90 */
91 if (attr_name[0] != 0)
92 snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
93 attr_name, k1);
94 else
95 snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
96 k1);
97
98 len = sizeof(value) - 1;
99 result =
100 asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
101
102 if (result == ASN1_ELEMENT_NOT_FOUND) {
103 gnutls_assert();
104 break;
105 }
106
107 if (result != ASN1_VALUE_NOT_FOUND) {
108 gnutls_assert();
109 result = _gnutls_asn2err(result);
110 goto cleanup;
111 }
112
113 /* Move to the attribute type and values
114 */
115 /* Read the OID
116 */
117 _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
118 tmpbuffer1);
119 _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), ".type");
120
121 len = sizeof(oid) - 1;
122 result =
123 asn1_read_value(asn1_struct, tmpbuffer3, oid, &len);
124
125 if (result == ASN1_ELEMENT_NOT_FOUND)
126 break;
127 else if (result != ASN1_SUCCESS) {
128 gnutls_assert();
129 result = _gnutls_asn2err(result);
130 goto cleanup;
131 }
132
133 if (strcmp(oid, given_oid) == 0) { /* Found the OID */
134
135 /* Read the Value
136 */
137 snprintf(tmpbuffer3, sizeof(tmpbuffer3),
138 "%s.values.?%u", tmpbuffer1, indx + 1);
139
140 len = sizeof(value) - 1;
141 result =
142 _gnutls_x509_read_value(asn1_struct,
143 tmpbuffer3, &td);
144
145 if (result != ASN1_SUCCESS) {
146 gnutls_assert();
147 result = _gnutls_asn2err(result);
148 goto cleanup;
149 }
150
151 if (raw == 0) {
152 result =
153 _gnutls_x509_dn_to_string
154 (oid, td.data, td.size, out);
155
156 _gnutls_free_datum(&td);
157
158 if (result < 0) {
159 gnutls_assert();
160 goto cleanup;
161 }
162 return 0;
163 } else { /* raw!=0 */
164 out->data = td.data;
165 out->size = td.size;
166
167 return 0;
168 }
169 }
170
171 }
172 while (1);
173
174 gnutls_assert();
175
176 result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
177
178 cleanup:
179 return result;
180 }
181
182 /* This function will attempt to set the requested attribute in
183 * the given X509v3 certificate.
184 *
185 * Critical will be either 0 or 1.
186 */
187 static int
add_attribute(ASN1_TYPE asn,const char * root,const char * attribute_id,const gnutls_datum_t * ext_data)188 add_attribute(ASN1_TYPE asn, const char *root, const char *attribute_id,
189 const gnutls_datum_t * ext_data)
190 {
191 int result;
192 char name[MAX_NAME_SIZE];
193
194 snprintf(name, sizeof(name), "%s", root);
195
196 /* Add a new attribute in the list.
197 */
198 result = asn1_write_value(asn, name, "NEW", 1);
199 if (result != ASN1_SUCCESS) {
200 gnutls_assert();
201 return _gnutls_asn2err(result);
202 }
203
204 snprintf(name, sizeof(name), "%s.?LAST.type", root);
205
206 result = asn1_write_value(asn, name, attribute_id, 1);
207 if (result != ASN1_SUCCESS) {
208 gnutls_assert();
209 return _gnutls_asn2err(result);
210 }
211
212 snprintf(name, sizeof(name), "%s.?LAST.values", root);
213
214 result = asn1_write_value(asn, name, "NEW", 1);
215 if (result != ASN1_SUCCESS) {
216 gnutls_assert();
217 return _gnutls_asn2err(result);
218 }
219
220 snprintf(name, sizeof(name), "%s.?LAST.values.?LAST", root);
221
222 result = _gnutls_x509_write_value(asn, name, ext_data);
223 if (result < 0) {
224 gnutls_assert();
225 return result;
226 }
227
228 return 0;
229 }
230
231
232 int
_x509_set_attribute(ASN1_TYPE asn,const char * root,const char * ext_id,const gnutls_datum_t * ext_data)233 _x509_set_attribute(ASN1_TYPE asn, const char *root,
234 const char *ext_id, const gnutls_datum_t * ext_data)
235 {
236 int result;
237 int k, len;
238 char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
239 char extnID[MAX_OID_SIZE];
240
241 /* Find the index of the given attribute.
242 */
243 k = 0;
244 do {
245 k++;
246
247 snprintf(name, sizeof(name), "%s.?%u", root, k);
248
249 len = sizeof(extnID) - 1;
250 result = asn1_read_value(asn, name, extnID, &len);
251
252 /* move to next
253 */
254
255 if (result == ASN1_ELEMENT_NOT_FOUND) {
256 break;
257 }
258
259 do {
260
261 _gnutls_str_cpy(name2, sizeof(name2), name);
262 _gnutls_str_cat(name2, sizeof(name2), ".type");
263
264 len = sizeof(extnID) - 1;
265 result = asn1_read_value(asn, name2, extnID, &len);
266
267 if (result == ASN1_ELEMENT_NOT_FOUND) {
268 gnutls_assert();
269 break;
270 } else if (result != ASN1_SUCCESS) {
271 gnutls_assert();
272 return _gnutls_asn2err(result);
273 }
274
275 /* Handle Extension
276 */
277 if (strcmp(extnID, ext_id) == 0) {
278 /* attribute was found
279 */
280 return overwrite_attribute(asn, root, k,
281 ext_data);
282 }
283
284
285 }
286 while (0);
287 }
288 while (1);
289
290 if (result == ASN1_ELEMENT_NOT_FOUND) {
291 return add_attribute(asn, root, ext_id, ext_data);
292 } else {
293 gnutls_assert();
294 return _gnutls_asn2err(result);
295 }
296
297
298 return 0;
299 }
300