removed unneeded headers.
[gnutls.git] / libextra / gnutls_ia.c
blob57dff81f577943ea421752648d37b23f9c2c0e77
1 /*
2 * Copyright (C) 2005, 2006, 2008, 2009, 2010 Free Software Foundation,
3 * Inc.
5 * Author: Simon Josefsson
7 * This file is part of GnuTLS-EXTRA.
9 * GnuTLS-extra is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * GnuTLS-extra is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "gnutls_int.h"
24 #include "gnutls_record.h"
25 #include "gnutls_errors.h"
26 #include "gnutls_num.h"
27 #include "gnutls_state.h"
28 #include <gnutls/extra.h>
29 #include <ext_inner_application.h>
31 #define CHECKSUM_SIZE 12
33 struct gnutls_ia_client_credentials_st
35 gnutls_ia_avp_func avp_func;
36 void *avp_ptr;
39 struct gnutls_ia_server_credentials_st
41 gnutls_ia_avp_func avp_func;
42 void *avp_ptr;
45 static const char server_finished_label[] = "server phase finished";
46 static const char client_finished_label[] = "client phase finished";
47 static const char inner_permutation_label[] = "inner secret permutation";
48 static const char challenge_label[] = "inner application challenge";
51 * The TLS/IA packet is the InnerApplication token, described as
52 * follows in draft-funk-tls-inner-application-extension-01.txt:
54 * enum {
55 * application_payload(0), intermediate_phase_finished(1),
56 * final_phase_finished(2), (255)
57 * } InnerApplicationType;
59 * struct {
60 * InnerApplicationType msg_type;
61 * uint24 length;
62 * select (InnerApplicationType) {
63 * case application_payload: ApplicationPayload;
64 * case intermediate_phase_finished: IntermediatePhaseFinished;
65 * case final_phase_finished: FinalPhaseFinished;
66 * } body;
67 * } InnerApplication;
71 /* Send TLS/IA data. If data==NULL && sizeofdata==NULL, then the last
72 send was interrupted for some reason, and then we try to send it
73 again. Returns the number of bytes sent, or an error code. If
74 this return E_AGAIN and E_INTERRUPTED, call this function again
75 with data==NULL&&sizeofdata=0NULL until it returns successfully. */
76 static ssize_t
77 _gnutls_send_inner_application (gnutls_session_t session,
78 gnutls_ia_apptype_t msg_type,
79 const char *data, size_t sizeofdata)
81 opaque *p = NULL;
82 size_t plen = 0;
83 ssize_t len;
85 if (data != NULL)
87 plen = sizeofdata + 4;
88 p = gnutls_malloc (plen);
89 if (!p)
91 gnutls_assert ();
92 return GNUTLS_E_MEMORY_ERROR;
95 *(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
96 _gnutls_write_uint24 (sizeofdata, p + 1);
97 memcpy (p + 4, data, sizeofdata);
100 len =
101 _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1,
102 EPOCH_WRITE_CURRENT, p, plen, MBUFFER_FLUSH);
104 if (p)
105 gnutls_free (p);
107 return len;
110 /* Receive TLS/IA data. Store received TLS/IA message type in
111 *MSG_TYPE, and the data in DATA of max SIZEOFDATA size. Return the
112 number of bytes read, or an error code. */
113 static ssize_t
114 _gnutls_recv_inner_application (gnutls_session_t session,
115 gnutls_ia_apptype_t * msg_type,
116 opaque * data, size_t sizeofdata)
118 ssize_t len;
119 uint32_t len24;
120 opaque pkt[4];
122 len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
123 if (len != 4)
125 gnutls_assert ();
126 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
129 *msg_type = pkt[0];
130 len24 = _gnutls_read_uint24 (&pkt[1]);
132 if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len24 != CHECKSUM_SIZE)
134 gnutls_assert ();
135 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
138 if (sizeofdata < len24)
140 /* XXX push back pkt to IA buffer? */
141 gnutls_assert ();
142 return GNUTLS_E_SHORT_MEMORY_BUFFER;
145 if (len24 > 0)
147 uint32_t tmplen = len24;
149 len24 = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
150 data, tmplen);
151 if (len24 != tmplen)
153 gnutls_assert ();
154 /* XXX Correct? */
155 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
159 return len24;
162 /* Apply the TLS PRF using the TLS/IA inner secret as keying material,
163 where the seed is the client random concatenated with the server
164 random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
165 respectively). LABEL and LABEL_SIZE is used as the label. The
166 result is placed in pre-allocated OUT of OUTSIZE length. */
167 static int
168 _gnutls_ia_prf (gnutls_session_t session,
169 size_t label_size,
170 const char *label,
171 size_t extra_size,
172 const char *extra, size_t outsize, opaque * out)
174 int ret;
175 opaque *seed;
176 size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size;
177 extension_priv_data_t epriv;
178 ia_ext_st *priv;
180 ret =
181 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
182 &epriv);
183 if (ret < 0)
185 gnutls_assert ();
186 return ret;
188 priv = epriv.ptr;
190 seed = gnutls_malloc (seedsize);
191 if (!seed)
193 gnutls_assert ();
194 return GNUTLS_E_MEMORY_ERROR;
197 memcpy (seed, session->security_parameters.server_random,
198 GNUTLS_RANDOM_SIZE);
199 memcpy (seed + GNUTLS_RANDOM_SIZE,
200 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
201 memcpy (seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size);
203 ret = _gnutls_PRF (session, priv->inner_secret,
204 GNUTLS_MASTER_SIZE,
205 label, label_size, seed, seedsize, outsize, out);
207 gnutls_free (seed);
209 return ret;
213 * gnutls_ia_permute_inner_secret:
214 * @session: is a #gnutls_session_t structure.
215 * @session_keys_size: Size of generated session keys (0 if none).
216 * @session_keys: Generated session keys, used to permute inner secret
217 * (NULL if none).
219 * Permute the inner secret using the generated session keys.
221 * This can be called in the TLS/IA AVP callback to mix any generated
222 * session keys with the TLS/IA inner secret.
224 * Return value: Return zero on success, or a negative error code.
227 gnutls_ia_permute_inner_secret (gnutls_session_t session,
228 size_t session_keys_size,
229 const char *session_keys)
231 extension_priv_data_t epriv;
232 ia_ext_st *priv;
233 int ret;
235 ret =
236 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
237 &epriv);
238 if (ret < 0)
240 gnutls_assert ();
241 return ret;
243 priv = epriv.ptr;
245 return _gnutls_ia_prf (session,
246 sizeof (inner_permutation_label) - 1,
247 inner_permutation_label,
248 session_keys_size,
249 session_keys,
250 GNUTLS_RANDOM_SIZE, priv->inner_secret);
254 * gnutls_ia_generate_challenge:
255 * @session: is a #gnutls_session_t structure.
256 * @buffer_size: size of output buffer.
257 * @buffer: pre-allocated buffer to contain @buffer_size bytes of output.
259 * Generate an application challenge that the client cannot control or
260 * predict, based on the TLS/IA inner secret.
262 * Return value: Returns 0 on success, or an negative error code.
265 gnutls_ia_generate_challenge (gnutls_session_t session,
266 size_t buffer_size, char *buffer)
268 return _gnutls_ia_prf (session,
269 sizeof (challenge_label) - 1,
270 challenge_label, 0, NULL, buffer_size, buffer);
274 * gnutls_ia_extract_inner_secret:
275 * @session: is a #gnutls_session_t structure.
276 * @buffer: pre-allocated buffer to hold 48 bytes of inner secret.
278 * Copy the 48 bytes large inner secret into the specified buffer
280 * This function is typically used after the TLS/IA handshake has
281 * concluded. The TLS/IA inner secret can be used as input to a PRF
282 * to derive session keys. Do not use the inner secret directly as a
283 * session key, because for a resumed session that does not include an
284 * application phase, the inner secret will be identical to the inner
285 * secret in the original session. It is important to include, for
286 * example, the client and server randomness when deriving a sesssion
287 * key from the inner secret.
289 void
290 gnutls_ia_extract_inner_secret (gnutls_session_t session, char *buffer)
292 extension_priv_data_t epriv;
293 ia_ext_st *priv;
294 int ret;
296 ret =
297 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
298 &epriv);
299 if (ret < 0)
301 gnutls_assert ();
302 return;
304 priv = epriv.ptr;
306 memcpy (buffer, priv->inner_secret, GNUTLS_MASTER_SIZE);
310 * gnutls_ia_endphase_send:
311 * @session: is a #gnutls_session_t structure.
312 * @final_p: Set iff this should signal the final phase.
314 * Send a TLS/IA end phase message.
316 * In the client, this should only be used to acknowledge an end phase
317 * message sent by the server.
319 * In the server, this can be called instead of gnutls_ia_send() if
320 * the server wishes to end an application phase.
322 * Return value: Return 0 on success, or an error code.
325 gnutls_ia_endphase_send (gnutls_session_t session, int final_p)
327 opaque local_checksum[CHECKSUM_SIZE];
328 int client = session->security_parameters.entity == GNUTLS_CLIENT;
329 const char *label = client ? client_finished_label : server_finished_label;
330 int size_of_label = client ? sizeof (client_finished_label) :
331 sizeof (server_finished_label);
332 ssize_t len;
333 int ret;
334 extension_priv_data_t epriv;
335 ia_ext_st *priv;
337 ret =
338 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
339 &epriv);
340 if (ret < 0)
342 gnutls_assert ();
343 return ret;
345 priv = epriv.ptr;
347 ret = _gnutls_PRF (session, priv->inner_secret,
348 GNUTLS_MASTER_SIZE, label, size_of_label - 1,
349 /* XXX specification unclear on seed. */
350 "", 0, CHECKSUM_SIZE, local_checksum);
351 if (ret < 0)
352 return ret;
354 len = _gnutls_send_inner_application
355 (session,
356 final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
357 GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);
359 /* XXX Instead of calling this function over and over...?
360 * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
361 * len = _gnutls_io_write_flush(session);
364 if (len < 0)
366 gnutls_assert ();
367 return len;
370 return 0;
374 * gnutls_ia_verify_endphase:
375 * @session: is a #gnutls_session_t structure.
376 * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
378 * Verify TLS/IA end phase checksum data. If verification fails, the
379 * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
380 * sie.
382 * This function is called when gnutls_ia_recv() return
383 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
384 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
386 * Return value: Return 0 on successful verification, or an error
387 * code. If the checksum verification of the end phase message fails,
388 * %GNUTLS_E_IA_VERIFY_FAILED is returned.
391 gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum)
393 char local_checksum[CHECKSUM_SIZE];
394 int client = session->security_parameters.entity == GNUTLS_CLIENT;
395 const char *label = client ? server_finished_label : client_finished_label;
396 int size_of_label = client ? sizeof (server_finished_label) :
397 sizeof (client_finished_label);
398 int ret;
399 extension_priv_data_t epriv;
400 ia_ext_st *priv;
402 ret =
403 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
404 &epriv);
405 if (ret < 0)
407 gnutls_assert ();
408 return ret;
410 priv = epriv.ptr;
412 ret = _gnutls_PRF (session, priv->inner_secret,
413 GNUTLS_MASTER_SIZE,
414 label, size_of_label - 1,
415 "", 0, CHECKSUM_SIZE, local_checksum);
416 if (ret < 0)
418 gnutls_assert ();
419 return ret;
422 if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
424 ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
425 GNUTLS_A_INNER_APPLICATION_VERIFICATION);
426 if (ret < 0)
428 gnutls_assert ();
429 return ret;
432 return GNUTLS_E_IA_VERIFY_FAILED;
435 return 0;
439 * gnutls_ia_send:
440 * @session: is a #gnutls_session_t structure.
441 * @data: contains the data to send
442 * @sizeofdata: is the length of the data
444 * Send TLS/IA application payload data. This function has the
445 * similar semantics with send(). The only difference is that it
446 * accepts a GnuTLS session, and uses different error codes.
448 * The TLS/IA protocol is synchronous, so you cannot send more than
449 * one packet at a time. The client always send the first packet.
451 * To finish an application phase in the server, use
452 * gnutls_ia_endphase_send(). The client cannot end an application
453 * phase unilaterally; rather, a client is required to respond with an
454 * endphase of its own if gnutls_ia_recv indicates that the server has
455 * sent one.
457 * If the EINTR is returned by the internal push function (the default
458 * is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
459 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
460 * this function again, with the same parameters; alternatively you
461 * could provide a %NULL pointer for data, and 0 for size.
463 * Returns: The number of bytes sent, or a negative error code.
465 ssize_t
466 gnutls_ia_send (gnutls_session_t session, const char *data, size_t sizeofdata)
468 ssize_t len;
470 len = _gnutls_send_inner_application (session,
471 GNUTLS_IA_APPLICATION_PAYLOAD,
472 data, sizeofdata);
474 return len;
478 * gnutls_ia_recv:
479 * @session: is a #gnutls_session_t structure.
480 * @data: the buffer that the data will be read into, must hold >= 12 bytes.
481 * @sizeofdata: the number of requested bytes, must be >= 12.
483 * Receive TLS/IA data. This function has the similar semantics with
484 * recv(). The only difference is that it accepts a GnuTLS session,
485 * and uses different error codes.
487 * If the server attempt to finish an application phase, this function
488 * will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
489 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. The caller should then invoke
490 * gnutls_ia_verify_endphase(), and if it runs the client side, also
491 * send an endphase message of its own using gnutls_ia_endphase_send.
493 * If EINTR is returned by the internal push function (the default is
494 * @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned. If
495 * GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
496 * this function again, with the same parameters; alternatively you
497 * could provide a NULL pointer for data, and 0 for size.
499 * Returns: The number of bytes received. A negative error code is
500 * returned in case of an error. The
501 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
502 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
503 * application phase finished message has been sent by the server.
505 ssize_t
506 gnutls_ia_recv (gnutls_session_t session, char *data, size_t sizeofdata)
508 gnutls_ia_apptype_t msg_type = 0;
509 ssize_t len;
511 len = _gnutls_recv_inner_application (session, &msg_type, data, sizeofdata);
513 if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
514 return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
515 else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
516 return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
518 return len;
521 /* XXX rewrite the following two functions as state machines, to
522 handle EAGAIN/EINTERRUPTED? just add more problems to callers,
523 though. */
525 static int
526 _gnutls_ia_client_handshake (gnutls_session_t session)
528 char *buf = NULL;
529 size_t buflen = 0;
530 char tmp[1024]; /* XXX */
531 ssize_t len;
532 int ret;
533 const struct gnutls_ia_client_credentials_st *cred =
534 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
536 if (cred == NULL)
537 return GNUTLS_E_INTERNAL_ERROR;
539 while (1)
541 char *avp;
542 size_t avplen;
544 ret = cred->avp_func (session, cred->avp_ptr,
545 buf, buflen, &avp, &avplen);
546 if (ret)
548 int tmpret;
549 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
550 GNUTLS_A_INNER_APPLICATION_FAILURE);
551 if (tmpret < 0)
552 gnutls_assert ();
553 return ret;
556 len = gnutls_ia_send (session, avp, avplen);
557 gnutls_free (avp);
558 if (len < 0)
559 return len;
561 len = gnutls_ia_recv (session, tmp, sizeof (tmp));
562 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
563 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
565 ret = gnutls_ia_verify_endphase (session, tmp);
566 if (ret < 0)
567 return ret;
569 ret = gnutls_ia_endphase_send
570 (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
571 if (ret < 0)
572 return ret;
575 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
577 buf = NULL;
578 buflen = 0;
579 continue;
581 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
582 break;
584 if (len < 0)
585 return len;
587 buflen = len;
588 buf = tmp;
591 return 0;
594 static int
595 _gnutls_ia_server_handshake (gnutls_session_t session)
597 gnutls_ia_apptype_t msg_type;
598 ssize_t len;
599 char buf[1024];
600 int ret;
601 const struct gnutls_ia_server_credentials_st *cred =
602 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
604 if (cred == NULL)
605 return GNUTLS_E_INTERNAL_ERROR;
609 char *avp;
610 size_t avplen;
612 len = gnutls_ia_recv (session, buf, sizeof (buf));
613 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
614 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
616 ret = gnutls_ia_verify_endphase (session, buf);
617 if (ret < 0)
618 return ret;
621 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
622 continue;
623 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
624 break;
626 if (len < 0)
627 return len;
629 avp = NULL;
630 avplen = 0;
632 ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
633 if (ret < 0)
635 int tmpret;
636 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
637 GNUTLS_A_INNER_APPLICATION_FAILURE);
638 if (tmpret < 0)
639 gnutls_assert ();
640 return ret;
643 msg_type = ret;
645 if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
647 ret = gnutls_ia_endphase_send (session, msg_type ==
648 GNUTLS_IA_FINAL_PHASE_FINISHED);
649 if (ret < 0)
650 return ret;
652 else
654 len = gnutls_ia_send (session, avp, avplen);
655 gnutls_free (avp);
656 if (len < 0)
657 return len;
660 while (1);
662 return 0;
666 * gnutls_ia_handshake_p:
667 * @session: is a #gnutls_session_t structure.
669 * Predicate to be used after gnutls_handshake() to decide whether to
670 * invoke gnutls_ia_handshake(). Usable by both clients and servers.
672 * Return value: non-zero if TLS/IA handshake is expected, zero
673 * otherwise.
676 gnutls_ia_handshake_p (gnutls_session_t session)
678 extension_priv_data_t epriv;
679 ia_ext_st *priv;
680 int ret;
682 ret =
683 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SERVER_NAME,
684 &epriv);
685 if (ret < 0)
687 gnutls_assert ();
688 return ret;
690 priv = epriv.ptr;
692 /* Either local side or peer doesn't do TLS/IA: don't do IA */
694 if (!(priv->flags & IA_ENABLE) || !(priv->flags & IA_PEER_ENABLE))
695 return 0;
697 /* Not resuming or we don't allow skipping on resumption locally: do IA */
699 if (!(priv->flags & IA_ALLOW_SKIP) || !gnutls_session_is_resumed (session))
700 return 1;
702 /* If we're resuming and we and the peer both allow skipping on resumption:
703 * don't do IA */
705 return !(priv->flags & IA_PEER_ALLOW_SKIP);
710 * gnutls_ia_handshake:
711 * @session: is a #gnutls_session_t structure.
713 * Perform a TLS/IA handshake. This should be called after
714 * gnutls_handshake() iff gnutls_ia_handshake_p().
716 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
717 * otherwise an error code is returned.
720 gnutls_ia_handshake (gnutls_session_t session)
722 int ret;
724 if (session->security_parameters.entity == GNUTLS_CLIENT)
725 ret = _gnutls_ia_client_handshake (session);
726 else
727 ret = _gnutls_ia_server_handshake (session);
729 return ret;
733 * gnutls_ia_allocate_client_credentials:
734 * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
736 * This structure is complex enough to manipulate directly thus this
737 * helper function is provided in order to allocate it.
739 * Adding this credential to a session will enable TLS/IA, and will
740 * require an Application Phase after the TLS handshake (if the server
741 * support TLS/IA). Use gnutls_ia_enable() to toggle the TLS/IA mode.
743 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
744 * an error code is returned.
747 gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
749 *sc = gnutls_calloc (1, sizeof (**sc));
751 if (*sc == NULL)
752 return GNUTLS_E_MEMORY_ERROR;
754 return 0;
758 * gnutls_ia_free_client_credentials:
759 * @sc: is a #gnutls_ia_client_credentials_t structure.
761 * This structure is complex enough to manipulate directly thus this
762 * helper function is provided in order to free (deallocate) it.
765 void
766 gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
768 gnutls_free (sc);
772 * gnutls_ia_set_client_avp_function:
773 * @cred: is a #gnutls_ia_client_credentials_t structure.
774 * @avp_func: is the callback function
776 * Set the TLS/IA AVP callback handler used for the session.
778 * The AVP callback is called to process AVPs received from the
779 * server, and to get a new AVP to send to the server.
781 * The callback's function form is:
782 * int (*avp_func) (gnutls_session_t session, void *ptr,
783 * const char *last, size_t lastlen,
784 * char **next, size_t *nextlen);
786 * The @session parameter is the #gnutls_session_t structure
787 * corresponding to the current session. The @ptr parameter is the
788 * application hook pointer, set through
789 * gnutls_ia_set_client_avp_ptr(). The AVP received from the server
790 * is present in @last of @lastlen size, which will be %NULL on the
791 * first invocation. The newly allocated output AVP to send to the
792 * server should be placed in *@next of *@nextlen size.
794 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
795 * generated session keys with the TLS/IA inner secret.
797 * Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
798 * error code to abort the TLS/IA handshake.
800 * Note that the callback must use allocate the @next parameter using
801 * gnutls_malloc(), because it is released via gnutls_free() by the
802 * TLS/IA handshake function.
805 void
806 gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
807 gnutls_ia_avp_func avp_func)
809 cred->avp_func = avp_func;
813 * gnutls_ia_set_client_avp_ptr:
814 * @cred: is a #gnutls_ia_client_credentials_t structure.
815 * @ptr: is the pointer
817 * Sets the pointer that will be provided to the TLS/IA callback
818 * function as the first argument.
820 void
821 gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
823 cred->avp_ptr = ptr;
827 * gnutls_ia_get_client_avp_ptr:
828 * @cred: is a #gnutls_ia_client_credentials_t structure.
830 * Returns the pointer that will be provided to the TLS/IA callback
831 * function as the first argument.
833 * Returns: The client callback data pointer.
835 void *
836 gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
838 return cred->avp_ptr;
842 * gnutls_ia_allocate_server_credentials:
843 * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
845 * This structure is complex enough to manipulate directly thus this
846 * helper function is provided in order to allocate it.
848 * Adding this credential to a session will enable TLS/IA, and will
849 * require an Application Phase after the TLS handshake (if the client
850 * support TLS/IA). Use gnutls_ia_enable() to toggle the TLS/IA mode.
852 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
853 * an error code is returned.
856 gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
858 *sc = gnutls_calloc (1, sizeof (**sc));
860 if (*sc == NULL)
861 return GNUTLS_E_MEMORY_ERROR;
863 return 0;
867 * gnutls_ia_free_server_credentials:
868 * @sc: is a #gnutls_ia_server_credentials_t structure.
870 * This structure is complex enough to manipulate directly thus this
871 * helper function is provided in order to free (deallocate) it.
874 void
875 gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
877 gnutls_free (sc);
881 * gnutls_ia_set_server_credentials_function:
882 * @cred: is a #gnutls_ia_server_credentials_t structure.
883 * @func: is the callback function
885 * Set the TLS/IA AVP callback handler used for the session.
887 * The callback's function form is:
888 * int (*avp_func) (gnutls_session_t session, void *ptr,
889 * const char *last, size_t lastlen,
890 * char **next, size_t *nextlen);
892 * The @session parameter is the #gnutls_session_t structure
893 * corresponding to the current session. The @ptr parameter is the
894 * application hook pointer, set through
895 * gnutls_ia_set_server_avp_ptr(). The AVP received from the client
896 * is present in @last of @lastlen size. The newly allocated output
897 * AVP to send to the client should be placed in *@next of *@nextlen
898 * size.
900 * The AVP callback is called to process incoming AVPs from the
901 * client, and to get a new AVP to send to the client. It can also be
902 * used to instruct the TLS/IA handshake to do go into the
903 * Intermediate or Final phases. It return a negative error code, or
904 * a #gnutls_ia_apptype_t message type.
906 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
907 * generated session keys with the TLS/IA inner secret.
909 * Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
910 * another AVP to the client, return
911 * %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
912 * IntermediatePhaseFinished message should be sent, and return
913 * %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
914 * FinalPhaseFinished message should be sent. In the last two cases,
915 * the contents of the @next and @nextlen parameter is not used.
917 * Note that the callback must use allocate the @next parameter using
918 * gnutls_malloc(), because it is released via gnutls_free() by the
919 * TLS/IA handshake function.
921 void
922 gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
923 gnutls_ia_avp_func avp_func)
925 cred->avp_func = avp_func;
929 * gnutls_ia_set_server_avp_ptr:
930 * @cred: is a #gnutls_ia_client_credentials_t structure.
931 * @ptr: is the pointer
933 * Sets the pointer that will be provided to the TLS/IA callback
934 * function as the first argument.
936 void
937 gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
939 cred->avp_ptr = ptr;
943 * gnutls_ia_get_server_avp_ptr:
944 * @cred: is a #gnutls_ia_client_credentials_t structure.
946 * Returns the pointer that will be provided to the TLS/IA callback
947 * function as the first argument.
949 * Returns: The server callback data pointer.
951 void *
952 gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
954 return cred->avp_ptr;
958 * gnutls_ia_enable:
959 * @session: is a #gnutls_session_t structure.
960 * @allow_skip_on_resume: non-zero if local party allows one to skip the
961 * TLS/IA application phases for a resumed session.
963 * Specify whether we must advertise support for the TLS/IA extension
964 * during the handshake.
966 * At the client side, we always advertise TLS/IA if gnutls_ia_enable
967 * was called before the handshake; at the server side, we also
968 * require that the client has advertised that it wants to run TLS/IA
969 * before including the advertisement, as required by the protocol.
971 * Similarly, at the client side we always advertise that we allow
972 * TLS/IA to be skipped for resumed sessions if @allow_skip_on_resume
973 * is non-zero; at the server side, we also require that the session
974 * is indeed resumable and that the client has also advertised that it
975 * allows TLS/IA to be skipped for resumed sessions.
977 * After the TLS handshake, call gnutls_ia_handshake_p() to find out
978 * whether both parties agreed to do a TLS/IA handshake, before
979 * calling gnutls_ia_handshake() or one of the lower level gnutls_ia_*
980 * functions.
982 void
983 gnutls_ia_enable (gnutls_session_t session, int allow_skip_on_resume)
985 extension_priv_data_t epriv;
986 ia_ext_st *priv;
988 priv = gnutls_calloc (1, sizeof (*priv));
989 if (priv == NULL)
991 gnutls_assert ();
992 return;
995 epriv.ptr = priv;
997 priv->flags |= IA_ENABLE;
998 if (allow_skip_on_resume)
999 priv->flags |= IA_ALLOW_SKIP;
1001 _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_INNER_APPLICATION,
1002 epriv);