1 /*
2  * Copyright (C) 2003-2016 Free Software Foundation, Inc.
3  *
4  * Authors: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  *
21  */
22 
23 #include "gnutls_int.h"
24 #include <datum.h>
25 #include <global.h>
26 #include "errors.h"
27 #include <common.h>
28 #include <gnutls/x509-ext.h>
29 #include <x509.h>
30 #include <x509_b64.h>
31 #include <x509_int.h>
32 #include <libtasn1.h>
33 #include <pk.h>
34 #include <pkcs11_int.h>
35 #include "urls.h"
36 
37 /**
38  * gnutls_x509_tlsfeatures_init:
39  * @f: The TLS features
40  *
41  * This function will initialize a X.509 TLS features extension structure
42  *
43  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
44  *   otherwise a negative error value.
45  *
46  * Since: 3.5.1
47  **/
gnutls_x509_tlsfeatures_init(gnutls_x509_tlsfeatures_t * f)48 int gnutls_x509_tlsfeatures_init(gnutls_x509_tlsfeatures_t *f)
49 {
50 	*f = gnutls_calloc(1, sizeof(struct gnutls_x509_tlsfeatures_st));
51 	if (*f == NULL)
52 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
53 
54 	return 0;
55 }
56 
57 /**
58  * gnutls_x509_tlsfeatures_deinit:
59  * @f: The TLS features
60  *
61  * This function will deinitialize a X.509 TLS features extension structure
62  *
63  * Since: 3.5.1
64  **/
gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t f)65 void gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t f)
66 {
67 	gnutls_free(f);
68 }
69 
70 /**
71  * gnutls_x509_tlsfeatures_get:
72  * @f: The TLS features
73  * @idx: The index of the feature to get
74  * @feature: If the function succeeds, the feature will be stored in this variable
75  *
76  * This function will get a feature from the X.509 TLS features
77  * extension structure.
78  *
79  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
80  *   otherwise a negative error value.
81  *
82  * Since: 3.5.1
83  **/
gnutls_x509_tlsfeatures_get(gnutls_x509_tlsfeatures_t f,unsigned idx,unsigned int * feature)84 int gnutls_x509_tlsfeatures_get(gnutls_x509_tlsfeatures_t f, unsigned idx, unsigned int *feature)
85 {
86 	if (f == NULL) {
87 		gnutls_assert();
88 		return GNUTLS_E_INVALID_REQUEST;
89 	}
90 
91 	if (idx >= f->size) {
92 		return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
93 	}
94 
95 	*feature = f->feature[idx];
96 	return 0;
97 }
98 
99 /**
100  * gnutls_x509_crt_get_tlsfeatures:
101  * @crt: A X.509 certificate
102  * @features: If the function succeeds, the
103  *   features will be stored in this variable.
104  * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
105  * @critical: the extension status
106  *
107  * This function will get the X.509 TLS features
108  * extension structure from the certificate. The
109  * returned structure needs to be freed using
110  * gnutls_x509_tlsfeatures_deinit().
111  *
112  * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
113  * then if the @features structure is empty this function will behave
114  * identically as if the flag was not set. Otherwise if there are elements
115  * in the @features structure then they will be merged with.
116  *
117  * Note that @features must be initialized prior to calling this function.
118  *
119  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
120  *   otherwise a negative error value.
121  *
122  * Since: 3.5.1
123  **/
gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t crt,gnutls_x509_tlsfeatures_t features,unsigned int flags,unsigned int * critical)124 int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t crt,
125 				    gnutls_x509_tlsfeatures_t features,
126 				    unsigned int flags,
127 				    unsigned int *critical)
128 {
129 	int ret;
130 	gnutls_datum_t der;
131 
132 	if (crt == NULL) {
133 		gnutls_assert();
134 		return GNUTLS_E_INVALID_REQUEST;
135 	}
136 
137 	if ((ret =
138 		 _gnutls_x509_crt_get_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, 0,
139 						&der, critical)) < 0)
140 	{
141 		return ret;
142 	}
143 
144 	if (der.size == 0 || der.data == NULL) {
145 		gnutls_assert();
146 		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
147 	}
148 
149 	ret = gnutls_x509_ext_import_tlsfeatures(&der, features, flags);
150 	if (ret < 0) {
151 		gnutls_assert();
152 		goto cleanup;
153 	}
154 
155 	ret = 0;
156  cleanup:
157 	gnutls_free(der.data);
158 	return ret;
159 }
160 
161 /**
162  * gnutls_x509_crt_set_tlsfeatures:
163  * @crt: A X.509 certificate
164  * @features: If the function succeeds, the
165  *   features will be added to the certificate.
166  *
167  * This function will set the certificates
168  * X.509 TLS extension from the given structure.
169  *
170  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
171  *   otherwise a negative error value.
172  *
173  * Since: 3.5.1
174  **/
gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt,gnutls_x509_tlsfeatures_t features)175 int gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt,
176 				    gnutls_x509_tlsfeatures_t features)
177 {
178 	int ret;
179 	gnutls_datum_t der;
180 
181 	if (crt == NULL || features == NULL) {
182 		gnutls_assert();
183 		return GNUTLS_E_INVALID_REQUEST;
184 	}
185 
186 	ret = gnutls_x509_ext_export_tlsfeatures(features, &der);
187 	if (ret < 0) {
188 		gnutls_assert();
189 		return ret;
190 	}
191 
192 	ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, &der, 0);
193 
194 	_gnutls_free_datum(&der);
195 
196 	if (ret < 0) {
197 		gnutls_assert();
198 	}
199 
200 	return ret;
201 }
202 
203 /**
204  * gnutls_x509_tls_features_check_crt:
205  * @feat: a set of TLSFeatures
206  * @cert: the certificate to be checked
207  *
208  * This function will check the provided certificate against the TLSFeatures
209  * set in @feat using the RFC7633 p.4.2.2 rules. It will check whether the certificate
210  * contains the features in @feat or a superset.
211  *
212  * Returns: non-zero if the provided certificate complies, and zero otherwise.
213  *
214  * Since: 3.5.1
215  **/
gnutls_x509_tlsfeatures_check_crt(gnutls_x509_tlsfeatures_t feat,gnutls_x509_crt_t cert)216 unsigned gnutls_x509_tlsfeatures_check_crt(gnutls_x509_tlsfeatures_t feat,
217 					   gnutls_x509_crt_t cert)
218 {
219 	int ret;
220 	gnutls_x509_tlsfeatures_t cfeat;
221 	unsigned i, j, uret, found;
222 
223 	if (feat->size == 0)
224 		return 1; /* shortcut; no constraints to check */
225 
226 	ret = gnutls_x509_tlsfeatures_init(&cfeat);
227 	if (ret < 0)
228 		return gnutls_assert_val(0);
229 
230 	ret = gnutls_x509_crt_get_tlsfeatures(cert, cfeat, 0, NULL);
231 	if (ret < 0) {
232 		gnutls_assert();
233 		uret = 0;
234 		goto cleanup;
235 	}
236 
237 	/* if cert's features cannot be a superset */
238 	if (feat->size > cfeat->size) {
239 		_gnutls_debug_log("certificate has %u, while issuer has %u tlsfeatures\n", cfeat->size, feat->size);
240 		gnutls_assert();
241 		uret = 0;
242 		goto cleanup;
243 	}
244 
245 	for (i=0;i<feat->size;i++) {
246 		found = 0;
247 		for (j=0;j<cfeat->size;j++) {
248 			if (feat->feature[i] == cfeat->feature[j]) {
249 				found = 1;
250 				break;
251 			}
252 		}
253 
254 		if (found == 0) {
255 			_gnutls_debug_log("feature %d was not found in cert\n", (int)feat->feature[i]);
256 			uret = 0;
257 			goto cleanup;
258 		}
259 	}
260 
261 	uret = 1;
262  cleanup:
263 	gnutls_x509_tlsfeatures_deinit(cfeat);
264 	return uret;
265 }
266