Guile: Fix `x509-certificate-dn-oid' and related functions.
[gnutls.git] / lib / ext_authz.c
blob30e1058116edf6620d83aabcc9cebe63b8a4df2d
1 /*
2 * Copyright (C) 2007 Free Software Foundation
3 * Author: Simon Josefsson
5 * This file is part of GNUTLS.
7 * The GNUTLS library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA
25 * This file implements the authz extensions in
26 * draft-housley-tls-authz-extns-07 using the supplemental handshake
27 * record type, which see RFC 4680 and gnutls_supplemental.c.
29 * There are three parts of this file. The first is the client hello
30 * and server hello extensions, which are used to negotiate use of
31 * supplemental authz data. If they successfully negotiate that the
32 * client will send some format(s) and/or the server will send some
33 * format(s), this will request that gnutls_handshake() invoke a
34 * supplemental phase in the corresponding direction.
36 * It may be possible that client authz data format type negotiation
37 * fails, but server authz data format type negotiation succeeds. In
38 * that case, only the server will send supplemental data, and the
39 * client will only expect to receive supplemental data.
41 * The second part is parsing and generating the authz supplemental
42 * data itself, by using the callbacks.
44 * The third part is the public APIs for use in the callbacks, and of
45 * course gnutls_authz_enable() to request that authz should be used.
48 #include "gnutls_int.h"
49 #include "gnutls_auth_int.h"
50 #include "gnutls_errors.h"
51 #include "gnutls_num.h"
52 #include <ext_authz.h>
54 static int
55 format_in_list_p (unsigned char format,
56 const unsigned char *data,
57 size_t data_size)
59 size_t i;
60 for (i = 0; i < data_size; i++)
61 if (format == data[i])
62 return 1;
63 return 0;
66 static int
67 recv_extension (gnutls_session_t session,
68 const opaque * data,
69 size_t data_size,
70 int *formats)
72 size_t total_size;
73 const int *in = formats;
74 int *out = formats;
76 if (data_size == 0)
78 gnutls_assert ();
79 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
82 total_size = *data++;
83 data_size--;
85 if (data_size != total_size)
87 gnutls_assert ();
88 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
91 while (*in)
92 if (format_in_list_p (*in - 1, data, data_size))
94 _gnutls_debug_log ("EXT[%x]: Keeping authz format %02x\n",
95 session, *in);
96 *out++ = *in++;
98 else
100 _gnutls_debug_log ("EXT[%x]: Disabling authz format %02x\n",
101 session, *in);
102 in++;
104 *out = 0;
106 return 0;
109 static int
110 send_extension (gnutls_session_t session,
111 opaque * data,
112 size_t _data_size,
113 int *authz_formats)
115 ssize_t data_size = _data_size;
116 size_t total_size;
117 opaque *sizepos;
119 if (!authz_formats[0])
120 return 0;
122 /* Make room for size. */
123 DECR_LENGTH_RET (data_size, 1, GNUTLS_E_SHORT_MEMORY_BUFFER);
124 sizepos = data++;
126 for (total_size = 0; authz_formats[total_size]; total_size++)
128 _gnutls_debug_log ("EXT[%x]: Sending authz format %02x\n",
129 session, authz_formats[total_size]);
130 DECR_LENGTH_RET (data_size, 1, GNUTLS_E_SHORT_MEMORY_BUFFER);
131 *data++ = authz_formats[total_size] - 1;
134 *sizepos = total_size;
136 return 1 + total_size;
140 _gnutls_authz_ext_client_recv_params (gnutls_session_t session,
141 const opaque * data,
142 size_t data_size)
144 int *client_formats =
145 session->security_parameters.extensions.authz_client_formats;
146 int ret;
148 ret = recv_extension (session, data, data_size, client_formats);
149 if (ret < 0)
150 return ret;
152 if (*client_formats)
154 if (session->security_parameters.entity == GNUTLS_CLIENT)
156 _gnutls_debug_log ("EXT[%x]: Will send supplemental data\n",
157 session);
158 session->security_parameters.extensions.do_send_supplemental = 1;
160 else
161 session->security_parameters.extensions.authz_recvd_client = 1;
164 return 0;
168 _gnutls_authz_ext_client_send_params (gnutls_session_t session,
169 opaque * data,
170 size_t _data_size)
172 int *client_formats =
173 session->security_parameters.extensions.authz_client_formats;
174 int ret;
176 /* Should we be sending this? */
177 if (session->security_parameters.entity == GNUTLS_SERVER
178 && !session->security_parameters.extensions.authz_recvd_client)
180 gnutls_assert ();
181 return 0;
184 ret = send_extension (session, data, _data_size, client_formats);
186 if (session->security_parameters.entity == GNUTLS_SERVER && ret > 0)
188 _gnutls_debug_log ("EXT[%x]: Will expect supplemental data\n",
189 session);
190 session->security_parameters.extensions.do_recv_supplemental = 1;
193 return ret;
197 _gnutls_authz_ext_server_recv_params (gnutls_session_t session,
198 const opaque * data,
199 size_t data_size)
201 int *server_formats =
202 session->security_parameters.extensions.authz_server_formats;
203 int ret;
205 ret = recv_extension (session, data, data_size, server_formats);
206 if (ret < 0)
207 return ret;
209 if (*server_formats)
211 if (session->security_parameters.entity == GNUTLS_CLIENT)
213 _gnutls_debug_log ("EXT[%x]: Will expect supplemental data\n",
214 session);
215 session->security_parameters.extensions.do_recv_supplemental = 1;
217 else
218 session->security_parameters.extensions.authz_recvd_server = 1;
221 return 0;
225 _gnutls_authz_ext_server_send_params (gnutls_session_t session,
226 opaque * data,
227 size_t _data_size)
229 int *server_formats =
230 session->security_parameters.extensions.authz_server_formats;
231 int ret;
233 /* Should we be sending this? */
234 if (session->security_parameters.entity == GNUTLS_SERVER
235 && !session->security_parameters.extensions.authz_recvd_server)
237 gnutls_assert ();
238 return 0;
241 ret = send_extension (session, data, _data_size, server_formats);
243 if (session->security_parameters.entity == GNUTLS_SERVER && ret > 0)
245 _gnutls_debug_log ("EXT[%x]: Will send supplemental data\n",
246 session);
247 session->security_parameters.extensions.do_send_supplemental = 1;
250 return ret;
254 _gnutls_authz_supp_recv_params (gnutls_session_t session,
255 const opaque * data,
256 size_t data_size)
258 int authz_formats[MAX_AUTHZ_FORMATS + 1];
259 gnutls_datum_t info[MAX_AUTHZ_FORMATS];
260 gnutls_datum_t hash[MAX_AUTHZ_FORMATS];
261 int hashtype[MAX_AUTHZ_FORMATS];
262 ssize_t dsize = data_size;
263 const opaque *p = data;
264 size_t i;
265 gnutls_authz_recv_callback_func callback =
266 session->security_parameters.extensions.authz_recv_callback;
268 if (!callback)
270 gnutls_assert ();
271 return 0;
274 /* XXX Will there be more than one data item for each authz format?
275 If so, we can't know the maximum size of the list of authz data,
276 so replace the static arrays with dynamically allocated lists.
277 Let's worry about that when someone reports it. */
279 i = 0;
282 DECR_LEN (dsize, 2);
283 authz_formats[i] = _gnutls_read_uint16 (p) + 1;
284 p += 2;
286 _gnutls_debug_log ("EXT[%x]: authz_format[%d]=%02x\n",
287 session, i, authz_formats[i]);
289 DECR_LEN (dsize, 2);
290 info[i].size = _gnutls_read_uint16 (p);
291 p += 2;
293 _gnutls_debug_log ("EXT[%x]: data[%d]=%d bytes\n",
294 session, i, info[i].size);
296 info[i].data = p;
298 DECR_LEN (dsize, info[i].size);
299 p += info[i].size;
301 if (authz_formats[i] == GNUTLS_AUTHZ_X509_ATTR_CERT_URL
302 || authz_formats[i] == GNUTLS_AUTHZ_SAML_ASSERTION_URL)
304 DECR_LEN (dsize, 1);
305 _gnutls_debug_log ("EXT[%x]: hashtype[%d]=%02x\n",
306 session, i, *p);
307 if (*p == '\x00')
308 hashtype[i] = GNUTLS_MAC_SHA1;
309 else if (*p == '\x01')
310 hashtype[i] = GNUTLS_MAC_SHA256;
311 else
313 gnutls_assert ();
314 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
316 p++;
318 hash[i].data = p;
319 hash[i].size = _gnutls_hash_get_algo_len (hashtype[i]);
321 _gnutls_debug_log ("EXT[%x]: hash[%d]=%d\n",
322 session, i, hash[i].size);
324 DECR_LEN (dsize, hash[i].size);
325 p += hash[i].size;
327 else
329 hashtype[i] = 0;
330 hash[i].data = NULL;
331 hash[i].size = 0;
334 i++;
336 if (i == MAX_AUTHZ_FORMATS)
338 gnutls_assert ();
339 return GNUTLS_E_SHORT_MEMORY_BUFFER;
342 while (dsize > 0);
344 authz_formats[i] = 0;
346 return callback (session, authz_formats, info, hashtype, hash);
350 _gnutls_authz_supp_send_params (gnutls_session_t session,
351 gnutls_buffer *buf)
353 int *server_formats =
354 session->security_parameters.extensions.authz_server_formats;
355 int *client_formats =
356 session->security_parameters.extensions.authz_client_formats;
357 gnutls_authz_send_callback_func callback =
358 session->security_parameters.extensions.authz_send_callback;
359 gnutls_buffer *authz_buf =
360 &session->security_parameters.extensions.authz_data;
361 int ret;
363 if (!callback)
365 gnutls_assert ();
366 return GNUTLS_E_INVALID_REQUEST;
369 _gnutls_buffer_init (authz_buf);
371 ret = callback (session, client_formats, server_formats);
372 if (ret < 0)
374 gnutls_assert ();
375 return ret;
378 ret = _gnutls_buffer_append (buf, authz_buf->data, authz_buf->length);
379 if (ret < 0)
381 gnutls_assert ();
382 return ret;
385 _gnutls_buffer_clear (authz_buf);
387 return ret;
390 static int
391 add_data (gnutls_session_t session,
392 const char *data,
393 size_t len,
394 gnutls_authz_data_format_type_t format,
395 gnutls_mac_algorithm_t hash_type,
396 const char *hash)
398 gnutls_buffer *buffer = &session->security_parameters.extensions.authz_data;
399 size_t hash_len = hash ? _gnutls_hash_get_algo_len (hash_type) : 0;
400 unsigned char str[4];
401 int ret;
403 if (len + 4 > 0xFFFF)
405 gnutls_assert();
406 return GNUTLS_E_INVALID_REQUEST;
409 if (hash && hash_type != GNUTLS_MAC_SHA256 && hash_type != GNUTLS_MAC_SHA1)
411 gnutls_assert();
412 return GNUTLS_E_INVALID_REQUEST;
415 str[0] = '\x00';
416 str[1] = format - 1;
418 str[2] = (len >> 8) & 0xFF;
419 str[3] = len & 0xFF;
421 ret = _gnutls_buffer_append (buffer, str, 4);
422 if (ret < 0)
424 gnutls_assert ();
425 return ret;
428 ret = _gnutls_buffer_append (buffer, data, len);
429 if (ret < 0)
431 gnutls_assert ();
432 return ret;
435 if (hash)
437 if (hash_type == GNUTLS_MAC_SHA1)
438 str[0] = '\x00';
439 else if (hash_type == GNUTLS_MAC_SHA256)
440 str[0] = '\x01';
442 ret = _gnutls_buffer_append (buffer, str, 1);
443 if (ret < 0)
445 gnutls_assert ();
446 return ret;
449 ret = _gnutls_buffer_append (buffer, hash, hash_len);
450 if (ret < 0)
452 gnutls_assert ();
453 return ret;
457 return 0;
461 * gnutls_authz_send_x509_attr_cert:
462 * @session: is a #gnutls_session_t structure.
463 * @data: buffer with a X.509 attribute certificate.
464 * @len: length of buffer.
466 * Send a X.509 attribute certificate as authorization data. This
467 * function may only be called inside a @send_callback set by
468 * gnutls_authz_enable().
470 * Returns: Returns 0 on success, or an error code on failures. If
471 * the supplied data was too long (the authorization extension only
472 * support 64kb large attribute certificates),
473 * %GNUTLS_E_INVALID_REQUEST is returned.
476 gnutls_authz_send_x509_attr_cert (gnutls_session_t session,
477 const char *data,
478 size_t len)
480 return add_data (session, data, len, GNUTLS_AUTHZ_X509_ATTR_CERT, 0, NULL);
484 * gnutls_authz_send_saml_assertion:
485 * @session: is a #gnutls_session_t structure.
486 * @data: buffer with a SAML assertion.
487 * @len: length of buffer.
489 * Send a SAML assertion as authorization data. This function may
490 * only be called inside a @send_callback set by
491 * gnutls_authz_enable().
493 * Returns: Returns 0 on success, or an error code on failures. If
494 * the supplied data was too long (the authorization extension only
495 * support 64kb large SAML assertions), %GNUTLS_E_INVALID_REQUEST is
496 * returned.
499 gnutls_authz_send_saml_assertion (gnutls_session_t session,
500 const char *data,
501 size_t len)
503 return add_data (session, data, len, GNUTLS_AUTHZ_SAML_ASSERTION, 0, NULL);
507 * gnutls_authz_send_x509_attr_cert_url:
508 * @session: is a #gnutls_session_t structure.
509 * @url: buffer with a URL pointing to X.509 attribute certificate.
510 * @urllen: length of buffer.
511 * @hash_type: type of hash in @hash.
512 * @hash: buffer with hash of URL target.
514 * Send a URL to an X.509 attribute certificate as authorization data,
515 * including a hash used to make sure the retrieved data was the
516 * intended data. This function may only be called inside a
517 * @send_callback set by gnutls_authz_enable().
519 * Returns: Returns 0 on success, or an error code on failures. If
520 * the supplied data was too long (the authorization extension only
521 * support 64kb large URLs), %GNUTLS_E_INVALID_REQUEST is returned.
524 gnutls_authz_send_x509_attr_cert_url (gnutls_session_t session,
525 const char *url,
526 size_t urllen,
527 gnutls_mac_algorithm_t hash_type,
528 const char *hash)
530 return add_data (session, url, urllen, GNUTLS_AUTHZ_X509_ATTR_CERT_URL,
531 hash_type, hash);
535 * gnutls_authz_send_saml_assertion_url:
536 * @session: is a #gnutls_session_t structure.
537 * @url: buffer with a URL pointing to a SAML assertion.
538 * @urllen: length of buffer.
539 * @hash_type: type of hash in @hash.
540 * @hash: buffer with hash of URL target.
542 * Send a URL to a SAML assertion as authorization data, including a
543 * hash used to make sure the retrieved data was the intended data.
544 * This function may only be called inside a @send_callback set by
545 * gnutls_authz_enable().
547 * Returns: Returns 0 on success, or an error code on failures. If
548 * the supplied data was too long (the authorization extension only
549 * support 64kb large URLs), %GNUTLS_E_INVALID_REQUEST is returned.
552 gnutls_authz_send_saml_assertion_url (gnutls_session_t session,
553 const char *url,
554 size_t urllen,
555 gnutls_mac_algorithm_t hash_type,
556 const char *hash)
558 return add_data (session, url, urllen, GNUTLS_AUTHZ_X509_ATTR_CERT_URL,
559 hash_type, hash);
563 * gnutls_authz_enable:
564 * @session: is a #gnutls_session_t structure.
565 * @client_formats: zero-terminated list of
566 * #gnutls_authz_data_format_type_t elements with authorization
567 * data formats.
568 * @server_formats: zero-terminated list of
569 * #gnutls_authz_data_format_type_t elements with authorization
570 * data formats.
571 * @recv_callback: your callback function which will receive
572 * authz information when it is received.
573 * @send_callback: your callback function which is responsible for
574 * generating authorization data to send.
576 * Indicate willingness to send and receive authorization data, and
577 * which formats.
579 * For clients, @client_formats indicate which formats the client is
580 * willing to send, and @server_formats indicate which formats the
581 * client can receive.
583 * For servers, @client_formats indicate which formats the server is
584 * willing to accept from the client, and @server_formats indicate
585 * which formats the server is willing to send. Before the list is
586 * sent to the client, the formats which the client do not support are
587 * removed. If no supported formats remains, either or both of the
588 * extensions will not be sent.
590 * The @send_callback is invoked during the handshake if negotiation
591 * of the authorization extension was successful. The function
592 * prototype is:
594 * int (*gnutls_authz_send_callback_func) (gnutls_session_t @session,
595 * const int *@client_formats, const int *@server_formats);
597 * The @client_format contains a list of successfully negotiated
598 * formats which the client may send data for to the server. The
599 * @server_formats contains a list of successfully neogitated formats
600 * which the server may send data for to the client. The callback is
601 * supposed to invoke gnutls_authz_send_x509_attr_cert(),
602 * gnutls_authz_send_saml_assertion(),
603 * gnutls_authz_send_x509_attr_cert_url(), or
604 * gnutls_authz_send_saml_assertion_url() for the data it wishes to
605 * send, passing along the @session parameter, and the data. The
606 * @client_format function should return 0 on success, or an error
607 * code, which may be used to abort the handshake on failures.
609 * The @recv_callback is invoked during the handshake when
610 * authorization data is received. The prototype of the callback
611 * should be:
613 * int (*gnutls_authz_recv_callback_func) (gnutls_session_t session,
614 * const char *authz_formats, gnutls_datum_t *datums);
616 * The @authz_formats contains a list of formats for which data where
617 * received. The data for each format is stored in the @datums array,
618 * where the data associated with the @authz_formats[0] format is
619 * stored in @datums[0]. The function should return 0 on success, but
620 * may return an error, which may cause the handshake to abort.
622 * Note that there is no guarantee that @send_callback or
623 * @recv_callback is invoked just because gnutls_authz_enable was
624 * invoked. Whether the callbacks are invoked depend on whether
625 * negotiation of the extension succeeds. Therefor, if verification
626 * of authorization data is done by the @recv_callback, care should be
627 * made that if the callback is never invoked, it is not interpretetd
628 * as successful authorization verification. It is suggested to add
629 * some logic check whether authorization data was successfully
630 * verified after the call to gnutls_handshake(). That logic could
631 * shut down the connection if the authorization data is insufficient.
633 * This function have no effect if it is called during a handshake.
635 void
636 gnutls_authz_enable (gnutls_session_t session,
637 const int *client_formats,
638 const int *server_formats,
639 gnutls_authz_recv_callback_func recv_callback,
640 gnutls_authz_send_callback_func send_callback)
642 int *session_client_formats =
643 session->security_parameters.extensions.authz_client_formats;
644 int *session_server_formats =
645 session->security_parameters.extensions.authz_server_formats;
646 size_t i;
648 if (session->internals.handshake_state != STATE0)
649 return;
651 for (i = 0; client_formats[i]; i++)
652 if (i < MAX_AUTHZ_FORMATS)
653 session_client_formats[i] = client_formats[i];
654 if (i < MAX_AUTHZ_FORMATS)
655 session_client_formats[i] = 0;
656 else
657 session_client_formats[MAX_AUTHZ_FORMATS] = 0;
659 for (i = 0; server_formats[i]; i++)
660 if (i < MAX_AUTHZ_FORMATS)
661 session_server_formats[i] = server_formats[i];
662 if (i < MAX_AUTHZ_FORMATS)
663 session_server_formats[i] = 0;
664 else
665 session_server_formats[MAX_AUTHZ_FORMATS] = 0;
667 session->security_parameters.extensions.authz_recv_callback = recv_callback;
668 session->security_parameters.extensions.authz_send_callback = send_callback;