Merge branch 'master' of git://repo.or.cz/gnutls
[gnutls.git] / libextra / gnutls_ia.c
blobc8cfcb7be57ffb7dcaafb7875df70a61c8d93786
1 /*
2 * Copyright (C) 2005, 2006 Free Software Foundation
4 * Author: Simon Josefsson
6 * This file is part of GNUTLS-EXTRA.
8 * GNUTLS-EXTRA is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * GNUTLS-EXTRA 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 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GNUTLS-EXTRA; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
25 #include "gnutls_int.h"
26 #include "gnutls_record.h"
27 #include "gnutls_errors.h"
28 #include "gnutls_num.h"
29 #include "gnutls_state.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 = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
102 if (p)
103 gnutls_free (p);
105 return len;
108 /* Receive TLS/IA data. Store received TLS/IA message type in
109 *MSG_TYPE, and the data in DATA of max SIZEOFDATA size. Return the
110 number of bytes read, or an error code. */
111 static ssize_t
112 _gnutls_recv_inner_application (gnutls_session_t session,
113 gnutls_ia_apptype_t * msg_type,
114 opaque * data, size_t sizeofdata)
116 ssize_t len;
117 opaque pkt[4];
119 len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
120 if (len != 4)
122 gnutls_assert ();
123 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
126 *msg_type = pkt[0];
127 len = _gnutls_read_uint24 (&pkt[1]);
129 if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len != CHECKSUM_SIZE)
131 gnutls_assert ();
132 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
135 if (sizeofdata < len)
137 /* XXX push back pkt to IA buffer? */
138 gnutls_assert ();
139 return GNUTLS_E_SHORT_MEMORY_BUFFER;
142 if (len > 0)
144 int tmplen = len;
146 len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
147 data, tmplen);
148 if (len != tmplen)
150 gnutls_assert ();
151 /* XXX Correct? */
152 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
156 return len;
159 /* Apply the TLS PRF using the TLS/IA inner secret as keying material,
160 where the seed is the client random concatenated with the server
161 random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
162 respectively). LABEL and LABEL_SIZE is used as the label. The
163 result is placed in pre-allocated OUT of OUTSIZE length. */
164 static int
165 _gnutls_ia_prf (gnutls_session_t session,
166 size_t label_size,
167 const char *label,
168 size_t extra_size,
169 const char *extra, size_t outsize, opaque * out)
171 int ret;
172 opaque *seed;
173 size_t seedsize = 2 * TLS_RANDOM_SIZE + extra_size;
175 seed = gnutls_malloc (seedsize);
176 if (!seed)
178 gnutls_assert ();
179 return GNUTLS_E_MEMORY_ERROR;
182 memcpy (seed, session->security_parameters.server_random, TLS_RANDOM_SIZE);
183 memcpy (seed + TLS_RANDOM_SIZE, session->security_parameters.client_random,
184 TLS_RANDOM_SIZE);
185 memcpy (seed + 2 * TLS_RANDOM_SIZE, extra, extra_size);
187 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
188 TLS_MASTER_SIZE,
189 label, label_size, seed, seedsize, outsize, out);
191 gnutls_free (seed);
193 return ret;
197 * gnutls_ia_permute_inner_secret:
198 * @session: is a #gnutls_session_t structure.
199 * @session_keys_size: Size of generated session keys (0 if none).
200 * @session_keys: Generated session keys, used to permute inner secret
201 * (NULL if none).
203 * Permute the inner secret using the generated session keys.
205 * This can be called in the TLS/IA AVP callback to mix any generated
206 * session keys with the TLS/IA inner secret.
208 * Return value: Return zero on success, or a negative error code.
211 gnutls_ia_permute_inner_secret (gnutls_session_t session,
212 size_t session_keys_size,
213 const char *session_keys)
215 return _gnutls_ia_prf (session,
216 sizeof (inner_permutation_label) - 1,
217 inner_permutation_label,
218 session_keys_size,
219 session_keys,
220 TLS_RANDOM_SIZE,
221 session->security_parameters.inner_secret);
225 * gnutls_ia_generate_challenge:
226 * @session: is a #gnutls_session_t structure.
227 * @buffer_size: size of output buffer.
228 * @buffer: pre-allocated buffer to contain @buffer_size bytes of output.
230 * Generate an application challenge that the client cannot control or
231 * predict, based on the TLS/IA inner secret.
233 * Return value: Returns 0 on success, or an negative error code.
236 gnutls_ia_generate_challenge (gnutls_session_t session,
237 size_t buffer_size, char *buffer)
239 return _gnutls_ia_prf (session,
240 sizeof (challenge_label) - 1,
241 challenge_label, 0, NULL, buffer_size, buffer);
245 * gnutls_ia_extract_inner_secret:
246 * @session: is a #gnutls_session_t structure.
247 * @buffer: pre-allocated buffer to hold 48 bytes of inner secret.
249 * Copy the 48 bytes large inner secret into the specified buffer
251 * This function is typically used after the TLS/IA handshake has
252 * concluded. The TLS/IA inner secret can be used as input to a PRF
253 * to derive session keys. Do not use the inner secret directly as a
254 * session key, because for a resumed session that does not include an
255 * application phase, the inner secret will be identical to the inner
256 * secret in the original session. It is important to include, for
257 * example, the client and server randomness when deriving a sesssion
258 * key from the inner secret.
260 void
261 gnutls_ia_extract_inner_secret (gnutls_session_t session, char *buffer)
263 memcpy (buffer, session->security_parameters.inner_secret, TLS_MASTER_SIZE);
267 * gnutls_ia_endphase_send:
268 * @session: is a #gnutls_session_t structure.
269 * @final_p: Set iff this should signal the final phase.
271 * Send a TLS/IA end phase message.
273 * In the client, this should only be used to acknowledge an end phase
274 * message sent by the server.
276 * In the server, this can be called instead of gnutls_ia_send() if
277 * the server wishes to end an application phase.
279 * Return value: Return 0 on success, or an error code.
282 gnutls_ia_endphase_send (gnutls_session_t session, int final_p)
284 opaque local_checksum[CHECKSUM_SIZE];
285 int client = session->security_parameters.entity == GNUTLS_CLIENT;
286 const char *label = client ? client_finished_label : server_finished_label;
287 int size_of_label = client ? sizeof (client_finished_label) :
288 sizeof (server_finished_label);
289 ssize_t len;
290 int ret;
292 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
293 TLS_MASTER_SIZE, label, size_of_label - 1,
294 /* XXX specification unclear on seed. */
295 "", 0, CHECKSUM_SIZE, local_checksum);
296 if (ret < 0)
297 return ret;
299 len = _gnutls_send_inner_application
300 (session,
301 final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
302 GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);
304 /* XXX Instead of calling this function over and over...?
305 * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
306 * len = _gnutls_io_write_flush(session);
309 if (len < 0)
311 gnutls_assert ();
312 return len;
315 return 0;
319 * gnutls_ia_verify_endphase:
320 * @session: is a #gnutls_session_t structure.
321 * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
323 * Verify TLS/IA end phase checksum data. If verification fails, the
324 * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
325 * sie.
327 * This function is called when gnutls_ia_recv() return
328 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
329 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
331 * Return value: Return 0 on successful verification, or an error
332 * code. If the checksum verification of the end phase message fails,
333 * %GNUTLS_E_IA_VERIFY_FAILED is returned.
336 gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum)
338 char local_checksum[CHECKSUM_SIZE];
339 int client = session->security_parameters.entity == GNUTLS_CLIENT;
340 const char *label = client ? server_finished_label : client_finished_label;
341 int size_of_label = client ? sizeof (server_finished_label) :
342 sizeof (client_finished_label);
343 int ret;
345 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
346 TLS_MASTER_SIZE,
347 label, size_of_label - 1,
348 "", 0, CHECKSUM_SIZE, local_checksum);
349 if (ret < 0)
351 gnutls_assert ();
352 return ret;
355 if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
357 ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
358 GNUTLS_A_INNER_APPLICATION_VERIFICATION);
359 if (ret < 0)
361 gnutls_assert ();
362 return ret;
365 return GNUTLS_E_IA_VERIFY_FAILED;
368 return 0;
372 * gnutls_ia_send: Send peer the specified TLS/IA data.
373 * @session: is a #gnutls_session_t structure.
374 * @data: contains the data to send
375 * @sizeofdata: is the length of the data
377 * Send TLS/IA application payload data. This function has the
378 * similar semantics with send(). The only difference is that is
379 * accepts a GNUTLS session, and uses different error codes.
381 * The TLS/IA protocol is synchronous, so you cannot send more than
382 * one packet at a time. The client always send the first packet.
384 * To finish an application phase in the server, use
385 * gnutls_ia_endphase_send(). The client cannot end an application
386 * phase unilaterally; rather, a client is required to respond with an
387 * endphase of its own if gnutls_ia_recv indicates that the server has
388 * sent one.
390 * If the EINTR is returned by the internal push function (the default
391 * is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
392 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
393 * this function again, with the same parameters; alternatively you
394 * could provide a %NULL pointer for data, and 0 for size.
396 * Returns the number of bytes sent, or a negative error code.
398 ssize_t
399 gnutls_ia_send (gnutls_session_t session, const char *data, size_t sizeofdata)
401 ssize_t len;
403 len = _gnutls_send_inner_application (session,
404 GNUTLS_IA_APPLICATION_PAYLOAD,
405 data, sizeofdata);
407 return len;
411 * gnutls_ia_recv - read data from the TLS/IA protocol
412 * @session: is a #gnutls_session_t structure.
413 * @data: the buffer that the data will be read into, must hold >= 12 bytes.
414 * @sizeofdata: the number of requested bytes, must be >= 12.
416 * Receive TLS/IA data. This function has the similar semantics with
417 * recv(). The only difference is that is accepts a GNUTLS session,
418 * and uses different error codes.
420 * If the server attempt to finish an application phase, this function
421 * will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
422 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. The caller should then invoke
423 * gnutls_ia_verify_endphase(), and if it runs the client side, also
424 * send an endphase message of its own using gnutls_ia_endphase_send.
426 * If EINTR is returned by the internal push function (the default is
427 * @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned. If
428 * GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
429 * this function again, with the same parameters; alternatively you
430 * could provide a NULL pointer for data, and 0 for size.
432 * Returns the number of bytes received. A negative error code is
433 * returned in case of an error. The
434 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
435 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
436 * application phase finished message has been sent by the server.
438 ssize_t
439 gnutls_ia_recv (gnutls_session_t session, char *data, size_t sizeofdata)
441 gnutls_ia_apptype_t msg_type;
442 ssize_t len;
444 len = _gnutls_recv_inner_application (session, &msg_type, data, sizeofdata);
446 if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
447 return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
448 else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
449 return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
451 return len;
454 /* XXX rewrite the following two functions as state machines, to
455 handle EAGAIN/EINTERRUPTED? just add more problems to callers,
456 though. */
459 _gnutls_ia_client_handshake (gnutls_session_t session)
461 char *buf = NULL;
462 size_t buflen = 0;
463 char tmp[1024]; /* XXX */
464 ssize_t len;
465 int ret;
466 const struct gnutls_ia_client_credentials_st *cred =
467 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
469 if (cred == NULL)
470 return GNUTLS_E_INTERNAL_ERROR;
472 while (1)
474 char *avp;
475 size_t avplen;
477 ret = cred->avp_func (session, cred->avp_ptr,
478 buf, buflen, &avp, &avplen);
479 if (ret)
481 int tmpret;
482 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
483 GNUTLS_A_INNER_APPLICATION_FAILURE);
484 if (tmpret < 0)
485 gnutls_assert ();
486 return ret;
489 len = gnutls_ia_send (session, avp, avplen);
490 gnutls_free (avp);
491 if (len < 0)
492 return len;
494 len = gnutls_ia_recv (session, tmp, sizeof (tmp));
495 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
496 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
498 ret = gnutls_ia_verify_endphase (session, tmp);
499 if (ret < 0)
500 return ret;
502 ret = gnutls_ia_endphase_send
503 (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
504 if (ret < 0)
505 return ret;
508 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
510 buf = NULL;
511 buflen = 0;
512 continue;
514 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
515 break;
517 if (len < 0)
518 return len;
520 buflen = len;
521 buf = tmp;
524 return 0;
528 _gnutls_ia_server_handshake (gnutls_session_t session)
530 gnutls_ia_apptype_t msg_type;
531 ssize_t len;
532 char buf[1024];
533 int ret;
534 const struct gnutls_ia_server_credentials_st *cred =
535 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
537 if (cred == NULL)
538 return GNUTLS_E_INTERNAL_ERROR;
542 char *avp;
543 size_t avplen;
545 len = gnutls_ia_recv (session, buf, sizeof (buf));
546 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
547 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
549 ret = gnutls_ia_verify_endphase (session, buf);
550 if (ret < 0)
551 return ret;
554 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
555 continue;
556 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
557 break;
559 if (len < 0)
560 return len;
562 avp = NULL;
563 avplen = 0;
565 ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
566 if (ret < 0)
568 int tmpret;
569 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
570 GNUTLS_A_INNER_APPLICATION_FAILURE);
571 if (tmpret < 0)
572 gnutls_assert ();
573 return ret;
576 msg_type = ret;
578 if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
580 ret = gnutls_ia_endphase_send (session, msg_type ==
581 GNUTLS_IA_FINAL_PHASE_FINISHED);
582 if (ret < 0)
583 return ret;
585 else
587 len = gnutls_ia_send (session, avp, avplen);
588 gnutls_free (avp);
589 if (len < 0)
590 return len;
593 while (1);
595 return 0;
599 * gnutls_ia_handshake_p:
600 * @session: is a #gnutls_session_t structure.
602 * Predicate to be used after gnutls_handshake() to decide whether to
603 * invoke gnutls_ia_handshake(). Usable by both clients and servers.
605 * Return value: non-zero if TLS/IA handshake is expected, zero
606 * otherwise.
609 gnutls_ia_handshake_p (gnutls_session_t session)
611 tls_ext_st *ext = &session->security_parameters.extensions;
613 /* Either local side or peer doesn't do TLS/IA: don't do IA */
615 if (!ext->gnutls_ia_enable || !ext->gnutls_ia_peer_enable)
616 return 0;
618 /* Not resuming or we don't allow skipping on resumption locally: do IA */
620 if (!ext->gnutls_ia_allowskip || !gnutls_session_is_resumed (session))
621 return 1;
623 /* If we're resuming and we and the peer both allow skipping on resumption:
624 * don't do IA */
626 return !ext->gnutls_ia_peer_allowskip;
631 * gnutls_ia_handshake:
632 * @session: is a #gnutls_session_t structure.
634 * Perform a TLS/IA handshake. This should be called after
635 * gnutls_handshake() iff gnutls_ia_handshake_p().
637 * Return 0 on success, or an error code.
640 gnutls_ia_handshake (gnutls_session_t session)
642 int ret;
644 if (session->security_parameters.entity == GNUTLS_CLIENT)
645 ret = _gnutls_ia_client_handshake (session);
646 else
647 ret = _gnutls_ia_server_handshake (session);
649 return ret;
653 * gnutls_ia_allocate_client_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
654 * @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
656 * This structure is complex enough to manipulate directly thus this
657 * helper function is provided in order to allocate it.
659 * Adding this credential to a session will enable TLS/IA, and will
660 * require an Application Phase after the TLS handshake (if the server
661 * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
662 * TLS/IA mode.
664 * Returns 0 on success.
667 gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
669 *sc = gnutls_calloc (1, sizeof (**sc));
671 if (*sc == NULL)
672 return GNUTLS_E_MEMORY_ERROR;
674 return 0;
678 * gnutls_ia_free_client_credentials - Used to free an allocated #gnutls_ia_client_credentials_t structure
679 * @sc: is an #gnutls_ia_client_credentials_t structure.
681 * This structure is complex enough to manipulate directly thus this
682 * helper function is provided in order to free (deallocate) it.
685 void
686 gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
688 gnutls_free (sc);
692 * gnutls_ia_set_client_avp_function - Used to set a AVP callback
693 * @cred: is a #gnutls_ia_client_credentials_t structure.
694 * @avp_func: is the callback function
696 * Set the TLS/IA AVP callback handler used for the session.
698 * The AVP callback is called to process AVPs received from the
699 * server, and to get a new AVP to send to the server.
701 * The callback's function form is:
702 * int (*avp_func) (gnutls_session_t session, void *ptr,
703 * const char *last, size_t lastlen,
704 * char **next, size_t *nextlen);
706 * The @session parameter is the #gnutls_session_t structure
707 * corresponding to the current session. The @ptr parameter is the
708 * application hook pointer, set through
709 * gnutls_ia_set_client_avp_ptr(). The AVP received from the server
710 * is present in @last of @lastlen size, which will be %NULL on the
711 * first invocation. The newly allocated output AVP to send to the
712 * server should be placed in *@next of *@nextlen size.
714 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
715 * generated session keys with the TLS/IA inner secret.
717 * Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
718 * error code to abort the TLS/IA handshake.
720 * Note that the callback must use allocate the @next parameter using
721 * gnutls_malloc(), because it is released via gnutls_free() by the
722 * TLS/IA handshake function.
725 void
726 gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
727 gnutls_ia_avp_func avp_func)
729 cred->avp_func = avp_func;
733 * gnutls_ia_set_client_avp_ptr - Sets a pointer to be sent to TLS/IA callback
734 * @cred: is a #gnutls_ia_client_credentials_t structure.
735 * @ptr: is the pointer
737 * Sets the pointer that will be provided to the TLS/IA callback
738 * function as the first argument.
741 void
742 gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
744 cred->avp_ptr = ptr;
748 * gnutls_ia_get_client_avp_ptr - Returns the pointer which is sent to TLS/IA callback
749 * @cred: is a #gnutls_ia_client_credentials_t structure.
751 * Returns the pointer that will be provided to the TLS/IA callback
752 * function as the first argument.
755 void *
756 gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
758 return cred->avp_ptr;
762 * gnutls_ia_allocate_server_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
763 * @sc: is a pointer to an #gnutls_ia_server_credentials_t structure.
765 * This structure is complex enough to manipulate directly thus this
766 * helper function is provided in order to allocate it.
768 * Adding this credential to a session will enable TLS/IA, and will
769 * require an Application Phase after the TLS handshake (if the client
770 * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
771 * TLS/IA mode.
773 * Returns 0 on success.
776 gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
778 *sc = gnutls_calloc (1, sizeof (**sc));
780 if (*sc == NULL)
781 return GNUTLS_E_MEMORY_ERROR;
783 return 0;
787 * gnutls_ia_free_server_credentials - Used to free an allocated #gnutls_ia_server_credentials_t structure
788 * @sc: is an #gnutls_ia_server_credentials_t structure.
790 * This structure is complex enough to manipulate directly thus this
791 * helper function is provided in order to free (deallocate) it.
794 void
795 gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
797 gnutls_free (sc);
801 * gnutls_ia_set_server_credentials_function - Used to set a AVP callback
802 * @cred: is a #gnutls_ia_server_credentials_t structure.
803 * @func: is the callback function
805 * Set the TLS/IA AVP callback handler used for the session.
807 * The callback's function form is:
808 * int (*avp_func) (gnutls_session_t session, void *ptr,
809 * const char *last, size_t lastlen,
810 * char **next, size_t *nextlen);
812 * The @session parameter is the #gnutls_session_t structure
813 * corresponding to the current session. The @ptr parameter is the
814 * application hook pointer, set through
815 * gnutls_ia_set_server_avp_ptr(). The AVP received from the client
816 * is present in @last of @lastlen size. The newly allocated output
817 * AVP to send to the client should be placed in *@next of *@nextlen
818 * size.
820 * The AVP callback is called to process incoming AVPs from the
821 * client, and to get a new AVP to send to the client. It can also be
822 * used to instruct the TLS/IA handshake to do go into the
823 * Intermediate or Final phases. It return a negative error code, or
824 * an #gnutls_ia_apptype_t message type.
826 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
827 * generated session keys with the TLS/IA inner secret.
829 * Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
830 * another AVP to the client, return
831 * %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
832 * IntermediatePhaseFinished message should be sent, and return
833 * %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
834 * FinalPhaseFinished message should be sent. In the last two cases,
835 * the contents of the @next and @nextlen parameter is not used.
837 * Note that the callback must use allocate the @next parameter using
838 * gnutls_malloc(), because it is released via gnutls_free() by the
839 * TLS/IA handshake function.
841 void
842 gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
843 gnutls_ia_avp_func avp_func)
845 cred->avp_func = avp_func;
849 * gnutls_ia_set_server_avp_ptr - Sets a pointer to be sent to TLS/IA callback
850 * @cred: is a #gnutls_ia_client_credentials_t structure.
851 * @ptr: is the pointer
853 * Sets the pointer that will be provided to the TLS/IA callback
854 * function as the first argument.
857 void
858 gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
860 cred->avp_ptr = ptr;
864 * gnutls_ia_get_server_avp_ptr - Returns the pointer which is sent to TLS/IA callback
865 * @cred: is a #gnutls_ia_client_credentials_t structure.
867 * Returns the pointer that will be provided to the TLS/IA callback
868 * function as the first argument.
871 void *
872 gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
874 return cred->avp_ptr;
878 * gnutls_ia_enable - Indicate willingness for TLS/IA application phases
879 * @session: is a #gnutls_session_t structure.
880 * @allow_skip_on_resume: non-zero if local party allows to skip the
881 * TLS/IA application phases for a resumed session.
883 * Specify whether we must advertise support for the TLS/IA extension
884 * during the handshake.
886 * At the client side, we always advertise TLS/IA if gnutls_ia_enable
887 * was called before the handshake; at the server side, we also
888 * require that the client has advertised that it wants to run TLS/IA
889 * before including the advertisement, as required by the protocol.
891 * Similarly, at the client side we always advertise that we allow
892 * TLS/IA to be skipped for resumed sessions if @allow_skip_on_resume
893 * is non-zero; at the server side, we also require that the session
894 * is indeed resumable and that the client has also advertised that it
895 * allows TLS/IA to be skipped for resumed sessions.
897 * After the TLS handshake, call gnutls_ia_handshake_p() to find out
898 * whether both parties agreed to do a TLS/IA handshake, before
899 * calling gnutls_ia_handshake() or one of the lower level gnutls_ia_*
900 * functions.
902 void
903 gnutls_ia_enable (gnutls_session_t session, int allow_skip_on_resume)
905 session->security_parameters.extensions.gnutls_ia_enable = 1;
906 session->security_parameters.extensions.gnutls_ia_allowskip =
907 allow_skip_on_resume;