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