/src/gnutls/lib/x509/tls_features.c
Line | Count | Source (jump to first uncovered line) |
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 | | **/ |
48 | | int gnutls_x509_tlsfeatures_init(gnutls_x509_tlsfeatures_t * f) |
49 | 0 | { |
50 | 0 | *f = gnutls_calloc(1, sizeof(struct gnutls_x509_tlsfeatures_st)); |
51 | 0 | if (*f == NULL) |
52 | 0 | return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); |
53 | | |
54 | 0 | return 0; |
55 | 0 | } |
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 | | **/ |
65 | | void gnutls_x509_tlsfeatures_deinit(gnutls_x509_tlsfeatures_t f) |
66 | 0 | { |
67 | 0 | gnutls_free(f); |
68 | 0 | } |
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 | | **/ |
84 | | int gnutls_x509_tlsfeatures_get(gnutls_x509_tlsfeatures_t f, unsigned idx, |
85 | | unsigned int *feature) |
86 | 0 | { |
87 | 0 | if (f == NULL) { |
88 | 0 | gnutls_assert(); |
89 | 0 | return GNUTLS_E_INVALID_REQUEST; |
90 | 0 | } |
91 | | |
92 | 0 | if (idx >= f->size) { |
93 | 0 | return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); |
94 | 0 | } |
95 | | |
96 | 0 | *feature = f->feature[idx]; |
97 | 0 | return 0; |
98 | 0 | } |
99 | | |
100 | | /** |
101 | | * gnutls_x509_crt_get_tlsfeatures: |
102 | | * @crt: A X.509 certificate |
103 | | * @features: If the function succeeds, the |
104 | | * features will be stored in this variable. |
105 | | * @flags: zero or %GNUTLS_EXT_FLAG_APPEND |
106 | | * @critical: the extension status |
107 | | * |
108 | | * This function will get the X.509 TLS features |
109 | | * extension structure from the certificate. The |
110 | | * returned structure needs to be freed using |
111 | | * gnutls_x509_tlsfeatures_deinit(). |
112 | | * |
113 | | * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND, |
114 | | * then if the @features structure is empty this function will behave |
115 | | * identically as if the flag was not set. Otherwise if there are elements |
116 | | * in the @features structure then they will be merged with. |
117 | | * |
118 | | * Note that @features must be initialized prior to calling this function. |
119 | | * |
120 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, |
121 | | * otherwise a negative error value. |
122 | | * |
123 | | * Since: 3.5.1 |
124 | | **/ |
125 | | int gnutls_x509_crt_get_tlsfeatures(gnutls_x509_crt_t crt, |
126 | | gnutls_x509_tlsfeatures_t features, |
127 | | unsigned int flags, unsigned int *critical) |
128 | 0 | { |
129 | 0 | int ret; |
130 | 0 | gnutls_datum_t der; |
131 | |
|
132 | 0 | if (crt == NULL) { |
133 | 0 | gnutls_assert(); |
134 | 0 | return GNUTLS_E_INVALID_REQUEST; |
135 | 0 | } |
136 | | |
137 | 0 | if ((ret = |
138 | 0 | _gnutls_x509_crt_get_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, |
139 | 0 | 0, &der, critical)) < 0) { |
140 | 0 | return ret; |
141 | 0 | } |
142 | | |
143 | 0 | if (der.size == 0 || der.data == NULL) { |
144 | 0 | gnutls_assert(); |
145 | 0 | return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; |
146 | 0 | } |
147 | | |
148 | 0 | ret = gnutls_x509_ext_import_tlsfeatures(&der, features, flags); |
149 | 0 | if (ret < 0) { |
150 | 0 | gnutls_assert(); |
151 | 0 | goto cleanup; |
152 | 0 | } |
153 | | |
154 | 0 | ret = 0; |
155 | 0 | cleanup: |
156 | 0 | gnutls_free(der.data); |
157 | 0 | return ret; |
158 | 0 | } |
159 | | |
160 | | /** |
161 | | * gnutls_x509_crt_set_tlsfeatures: |
162 | | * @crt: A X.509 certificate |
163 | | * @features: If the function succeeds, the |
164 | | * features will be added to the certificate. |
165 | | * |
166 | | * This function will set the certificates |
167 | | * X.509 TLS extension from the given structure. |
168 | | * |
169 | | * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, |
170 | | * otherwise a negative error value. |
171 | | * |
172 | | * Since: 3.5.1 |
173 | | **/ |
174 | | int gnutls_x509_crt_set_tlsfeatures(gnutls_x509_crt_t crt, |
175 | | gnutls_x509_tlsfeatures_t features) |
176 | 0 | { |
177 | 0 | int ret; |
178 | 0 | gnutls_datum_t der; |
179 | |
|
180 | 0 | if (crt == NULL || features == NULL) { |
181 | 0 | gnutls_assert(); |
182 | 0 | return GNUTLS_E_INVALID_REQUEST; |
183 | 0 | } |
184 | | |
185 | 0 | ret = gnutls_x509_ext_export_tlsfeatures(features, &der); |
186 | 0 | if (ret < 0) { |
187 | 0 | gnutls_assert(); |
188 | 0 | return ret; |
189 | 0 | } |
190 | | |
191 | 0 | ret = |
192 | 0 | _gnutls_x509_crt_set_extension(crt, GNUTLS_X509EXT_OID_TLSFEATURES, |
193 | 0 | &der, 0); |
194 | |
|
195 | 0 | _gnutls_free_datum(&der); |
196 | |
|
197 | 0 | if (ret < 0) { |
198 | 0 | gnutls_assert(); |
199 | 0 | } |
200 | |
|
201 | 0 | return ret; |
202 | 0 | } |
203 | | |
204 | | /** |
205 | | * gnutls_x509_tls_features_check_crt: |
206 | | * @feat: a set of TLSFeatures |
207 | | * @cert: the certificate to be checked |
208 | | * |
209 | | * This function will check the provided certificate against the TLSFeatures |
210 | | * set in @feat using the RFC7633 p.4.2.2 rules. It will check whether the certificate |
211 | | * contains the features in @feat or a superset. |
212 | | * |
213 | | * Returns: non-zero if the provided certificate complies, and zero otherwise. |
214 | | * |
215 | | * Since: 3.5.1 |
216 | | **/ |
217 | | unsigned gnutls_x509_tlsfeatures_check_crt(gnutls_x509_tlsfeatures_t feat, |
218 | | gnutls_x509_crt_t cert) |
219 | 0 | { |
220 | 0 | int ret; |
221 | 0 | gnutls_x509_tlsfeatures_t cfeat; |
222 | 0 | unsigned i, j, uret, found; |
223 | |
|
224 | 0 | if (feat->size == 0) |
225 | 0 | return 1; /* shortcut; no constraints to check */ |
226 | | |
227 | 0 | ret = gnutls_x509_tlsfeatures_init(&cfeat); |
228 | 0 | if (ret < 0) |
229 | 0 | return gnutls_assert_val(0); |
230 | | |
231 | 0 | ret = gnutls_x509_crt_get_tlsfeatures(cert, cfeat, 0, NULL); |
232 | 0 | if (ret < 0) { |
233 | 0 | gnutls_assert(); |
234 | 0 | uret = 0; |
235 | 0 | goto cleanup; |
236 | 0 | } |
237 | | |
238 | | /* if cert's features cannot be a superset */ |
239 | 0 | if (feat->size > cfeat->size) { |
240 | 0 | _gnutls_debug_log |
241 | 0 | ("certificate has %u, while issuer has %u tlsfeatures\n", |
242 | 0 | cfeat->size, feat->size); |
243 | 0 | gnutls_assert(); |
244 | 0 | uret = 0; |
245 | 0 | goto cleanup; |
246 | 0 | } |
247 | | |
248 | 0 | for (i = 0; i < feat->size; i++) { |
249 | 0 | found = 0; |
250 | 0 | for (j = 0; j < cfeat->size; j++) { |
251 | 0 | if (feat->feature[i] == cfeat->feature[j]) { |
252 | 0 | found = 1; |
253 | 0 | break; |
254 | 0 | } |
255 | 0 | } |
256 | |
|
257 | 0 | if (found == 0) { |
258 | 0 | _gnutls_debug_log("feature %d was not found in cert\n", |
259 | 0 | (int)feat->feature[i]); |
260 | 0 | uret = 0; |
261 | 0 | goto cleanup; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 0 | uret = 1; |
266 | 0 | cleanup: |
267 | 0 | gnutls_x509_tlsfeatures_deinit(cfeat); |
268 | 0 | return uret; |
269 | 0 | } |