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