Bump versions.
[gnutls.git] / libextra / gnutls_ia.c
blob438a765744ff85ff7a9b3c8abb2f715edd18e3c5
1 /*
2 * Copyright (C) 2005, 2006, 2008, 2009 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 modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GNUTLS-EXTRA is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "gnutls_int.h"
23 #include "gnutls_record.h"
24 #include "gnutls_errors.h"
25 #include "gnutls_num.h"
26 #include "gnutls_state.h"
27 #include <gnutls/extra.h>
29 #define CHECKSUM_SIZE 12
31 struct gnutls_ia_client_credentials_st
33 gnutls_ia_avp_func avp_func;
34 void *avp_ptr;
37 struct gnutls_ia_server_credentials_st
39 gnutls_ia_avp_func avp_func;
40 void *avp_ptr;
43 static const char server_finished_label[] = "server phase finished";
44 static const char client_finished_label[] = "client phase finished";
45 static const char inner_permutation_label[] = "inner secret permutation";
46 static const char challenge_label[] = "inner application challenge";
49 * The TLS/IA packet is the InnerApplication token, described as
50 * follows in draft-funk-tls-inner-application-extension-01.txt:
52 * enum {
53 * application_payload(0), intermediate_phase_finished(1),
54 * final_phase_finished(2), (255)
55 * } InnerApplicationType;
57 * struct {
58 * InnerApplicationType msg_type;
59 * uint24 length;
60 * select (InnerApplicationType) {
61 * case application_payload: ApplicationPayload;
62 * case intermediate_phase_finished: IntermediatePhaseFinished;
63 * case final_phase_finished: FinalPhaseFinished;
64 * } body;
65 * } InnerApplication;
69 /* Send TLS/IA data. If data==NULL && sizeofdata==NULL, then the last
70 send was interrupted for some reason, and then we try to send it
71 again. Returns the number of bytes sent, or an error code. If
72 this return E_AGAIN and E_INTERRUPTED, call this function again
73 with data==NULL&&sizeofdata=0NULL until it returns successfully. */
74 static ssize_t
75 _gnutls_send_inner_application (gnutls_session_t session,
76 gnutls_ia_apptype_t msg_type,
77 const char *data, size_t sizeofdata)
79 opaque *p = NULL;
80 size_t plen = 0;
81 ssize_t len;
83 if (data != NULL)
85 plen = sizeofdata + 4;
86 p = gnutls_malloc (plen);
87 if (!p)
89 gnutls_assert ();
90 return GNUTLS_E_MEMORY_ERROR;
93 *(unsigned char *) p = (unsigned char) (msg_type & 0xFF);
94 _gnutls_write_uint24 (sizeofdata, p + 1);
95 memcpy (p + 4, data, sizeofdata);
98 len = _gnutls_send_int (session, GNUTLS_INNER_APPLICATION, -1, p, plen);
100 if (p)
101 gnutls_free (p);
103 return len;
106 /* Receive TLS/IA data. Store received TLS/IA message type in
107 *MSG_TYPE, and the data in DATA of max SIZEOFDATA size. Return the
108 number of bytes read, or an error code. */
109 static ssize_t
110 _gnutls_recv_inner_application (gnutls_session_t session,
111 gnutls_ia_apptype_t * msg_type,
112 opaque * data, size_t sizeofdata)
114 ssize_t len;
115 uint32_t len24;
116 opaque pkt[4];
118 len = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1, pkt, 4);
119 if (len != 4)
121 gnutls_assert ();
122 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
125 *msg_type = pkt[0];
126 len24 = _gnutls_read_uint24 (&pkt[1]);
128 if (*msg_type != GNUTLS_IA_APPLICATION_PAYLOAD && len24 != CHECKSUM_SIZE)
130 gnutls_assert ();
131 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
134 if (sizeofdata < len24)
136 /* XXX push back pkt to IA buffer? */
137 gnutls_assert ();
138 return GNUTLS_E_SHORT_MEMORY_BUFFER;
141 if (len24 > 0)
143 uint32_t tmplen = len24;
145 len24 = _gnutls_recv_int (session, GNUTLS_INNER_APPLICATION, -1,
146 data, tmplen);
147 if (len24 != tmplen)
149 gnutls_assert ();
150 /* XXX Correct? */
151 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
155 return len24;
158 /* Apply the TLS PRF using the TLS/IA inner secret as keying material,
159 where the seed is the client random concatenated with the server
160 random concatenated EXTRA of EXTRA_SIZE length (which can be NULL/0
161 respectively). LABEL and LABEL_SIZE is used as the label. The
162 result is placed in pre-allocated OUT of OUTSIZE length. */
163 static int
164 _gnutls_ia_prf (gnutls_session_t session,
165 size_t label_size,
166 const char *label,
167 size_t extra_size,
168 const char *extra, size_t outsize, opaque * out)
170 int ret;
171 opaque *seed;
172 size_t seedsize = 2 * GNUTLS_RANDOM_SIZE + extra_size;
174 seed = gnutls_malloc (seedsize);
175 if (!seed)
177 gnutls_assert ();
178 return GNUTLS_E_MEMORY_ERROR;
181 memcpy (seed, session->security_parameters.server_random,
182 GNUTLS_RANDOM_SIZE);
183 memcpy (seed + GNUTLS_RANDOM_SIZE,
184 session->security_parameters.client_random, GNUTLS_RANDOM_SIZE);
185 memcpy (seed + 2 * GNUTLS_RANDOM_SIZE, extra, extra_size);
187 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
188 GNUTLS_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 GNUTLS_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,
264 GNUTLS_MASTER_SIZE);
268 * gnutls_ia_endphase_send:
269 * @session: is a #gnutls_session_t structure.
270 * @final_p: Set iff this should signal the final phase.
272 * Send a TLS/IA end phase message.
274 * In the client, this should only be used to acknowledge an end phase
275 * message sent by the server.
277 * In the server, this can be called instead of gnutls_ia_send() if
278 * the server wishes to end an application phase.
280 * Return value: Return 0 on success, or an error code.
283 gnutls_ia_endphase_send (gnutls_session_t session, int final_p)
285 opaque local_checksum[CHECKSUM_SIZE];
286 int client = session->security_parameters.entity == GNUTLS_CLIENT;
287 const char *label = client ? client_finished_label : server_finished_label;
288 int size_of_label = client ? sizeof (client_finished_label) :
289 sizeof (server_finished_label);
290 ssize_t len;
291 int ret;
293 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
294 GNUTLS_MASTER_SIZE, label, size_of_label - 1,
295 /* XXX specification unclear on seed. */
296 "", 0, CHECKSUM_SIZE, local_checksum);
297 if (ret < 0)
298 return ret;
300 len = _gnutls_send_inner_application
301 (session,
302 final_p ? GNUTLS_IA_FINAL_PHASE_FINISHED :
303 GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED, local_checksum, CHECKSUM_SIZE);
305 /* XXX Instead of calling this function over and over...?
306 * while (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
307 * len = _gnutls_io_write_flush(session);
310 if (len < 0)
312 gnutls_assert ();
313 return len;
316 return 0;
320 * gnutls_ia_verify_endphase:
321 * @session: is a #gnutls_session_t structure.
322 * @checksum: 12-byte checksum data, received from gnutls_ia_recv().
324 * Verify TLS/IA end phase checksum data. If verification fails, the
325 * %GNUTLS_A_INNER_APPLICATION_VERIFICATION alert is sent to the other
326 * sie.
328 * This function is called when gnutls_ia_recv() return
329 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
330 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED.
332 * Return value: Return 0 on successful verification, or an error
333 * code. If the checksum verification of the end phase message fails,
334 * %GNUTLS_E_IA_VERIFY_FAILED is returned.
337 gnutls_ia_verify_endphase (gnutls_session_t session, const char *checksum)
339 char local_checksum[CHECKSUM_SIZE];
340 int client = session->security_parameters.entity == GNUTLS_CLIENT;
341 const char *label = client ? server_finished_label : client_finished_label;
342 int size_of_label = client ? sizeof (server_finished_label) :
343 sizeof (client_finished_label);
344 int ret;
346 ret = _gnutls_PRF (session, session->security_parameters.inner_secret,
347 GNUTLS_MASTER_SIZE,
348 label, size_of_label - 1,
349 "", 0, CHECKSUM_SIZE, local_checksum);
350 if (ret < 0)
352 gnutls_assert ();
353 return ret;
356 if (memcmp (local_checksum, checksum, CHECKSUM_SIZE) != 0)
358 ret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
359 GNUTLS_A_INNER_APPLICATION_VERIFICATION);
360 if (ret < 0)
362 gnutls_assert ();
363 return ret;
366 return GNUTLS_E_IA_VERIFY_FAILED;
369 return 0;
373 * gnutls_ia_send: Send peer the specified TLS/IA data.
374 * @session: is a #gnutls_session_t structure.
375 * @data: contains the data to send
376 * @sizeofdata: is the length of the data
378 * Send TLS/IA application payload data. This function has the
379 * similar semantics with send(). The only difference is that it
380 * accepts a GnuTLS session, and uses different error codes.
382 * The TLS/IA protocol is synchronous, so you cannot send more than
383 * one packet at a time. The client always send the first packet.
385 * To finish an application phase in the server, use
386 * gnutls_ia_endphase_send(). The client cannot end an application
387 * phase unilaterally; rather, a client is required to respond with an
388 * endphase of its own if gnutls_ia_recv indicates that the server has
389 * sent one.
391 * If the EINTR is returned by the internal push function (the default
392 * is send()} then %GNUTLS_E_INTERRUPTED will be returned. If
393 * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must call
394 * this function again, with the same parameters; alternatively you
395 * could provide a %NULL pointer for data, and 0 for size.
397 * Returns: The number of bytes sent, or a negative error code.
399 ssize_t
400 gnutls_ia_send (gnutls_session_t session, const char *data, size_t sizeofdata)
402 ssize_t len;
404 len = _gnutls_send_inner_application (session,
405 GNUTLS_IA_APPLICATION_PAYLOAD,
406 data, sizeofdata);
408 return len;
412 * gnutls_ia_recv - read data from the TLS/IA protocol
413 * @session: is a #gnutls_session_t structure.
414 * @data: the buffer that the data will be read into, must hold >= 12 bytes.
415 * @sizeofdata: the number of requested bytes, must be >= 12.
417 * Receive TLS/IA data. This function has the similar semantics with
418 * recv(). The only difference is that it accepts a GnuTLS session,
419 * and uses different error codes.
421 * If the server attempt to finish an application phase, this function
422 * will return %GNUTLS_E_WARNING_IA_IPHF_RECEIVED or
423 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED. The caller should then invoke
424 * gnutls_ia_verify_endphase(), and if it runs the client side, also
425 * send an endphase message of its own using gnutls_ia_endphase_send.
427 * If EINTR is returned by the internal push function (the default is
428 * @code{recv()}) then GNUTLS_E_INTERRUPTED will be returned. If
429 * GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN is returned, you must call
430 * this function again, with the same parameters; alternatively you
431 * could provide a NULL pointer for data, and 0 for size.
433 * Returns: The number of bytes received. A negative error code is
434 * returned in case of an error. The
435 * %GNUTLS_E_WARNING_IA_IPHF_RECEIVED and
436 * %GNUTLS_E_WARNING_IA_FPHF_RECEIVED errors are returned when an
437 * application phase finished message has been sent by the server.
439 ssize_t
440 gnutls_ia_recv (gnutls_session_t session, char *data, size_t sizeofdata)
442 gnutls_ia_apptype_t msg_type = 0;
443 ssize_t len;
445 len = _gnutls_recv_inner_application (session, &msg_type, data, sizeofdata);
447 if (msg_type == GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED)
448 return GNUTLS_E_WARNING_IA_IPHF_RECEIVED;
449 else if (msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED)
450 return GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
452 return len;
455 /* XXX rewrite the following two functions as state machines, to
456 handle EAGAIN/EINTERRUPTED? just add more problems to callers,
457 though. */
459 static int
460 _gnutls_ia_client_handshake (gnutls_session_t session)
462 char *buf = NULL;
463 size_t buflen = 0;
464 char tmp[1024]; /* XXX */
465 ssize_t len;
466 int ret;
467 const struct gnutls_ia_client_credentials_st *cred =
468 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
470 if (cred == NULL)
471 return GNUTLS_E_INTERNAL_ERROR;
473 while (1)
475 char *avp;
476 size_t avplen;
478 ret = cred->avp_func (session, cred->avp_ptr,
479 buf, buflen, &avp, &avplen);
480 if (ret)
482 int tmpret;
483 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
484 GNUTLS_A_INNER_APPLICATION_FAILURE);
485 if (tmpret < 0)
486 gnutls_assert ();
487 return ret;
490 len = gnutls_ia_send (session, avp, avplen);
491 gnutls_free (avp);
492 if (len < 0)
493 return len;
495 len = gnutls_ia_recv (session, tmp, sizeof (tmp));
496 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
497 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
499 ret = gnutls_ia_verify_endphase (session, tmp);
500 if (ret < 0)
501 return ret;
503 ret = gnutls_ia_endphase_send
504 (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED);
505 if (ret < 0)
506 return ret;
509 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
511 buf = NULL;
512 buflen = 0;
513 continue;
515 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
516 break;
518 if (len < 0)
519 return len;
521 buflen = len;
522 buf = tmp;
525 return 0;
528 static int
529 _gnutls_ia_server_handshake (gnutls_session_t session)
531 gnutls_ia_apptype_t msg_type;
532 ssize_t len;
533 char buf[1024];
534 int ret;
535 const struct gnutls_ia_server_credentials_st *cred =
536 _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL);
538 if (cred == NULL)
539 return GNUTLS_E_INTERNAL_ERROR;
543 char *avp;
544 size_t avplen;
546 len = gnutls_ia_recv (session, buf, sizeof (buf));
547 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
548 len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
550 ret = gnutls_ia_verify_endphase (session, buf);
551 if (ret < 0)
552 return ret;
555 if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED)
556 continue;
557 else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)
558 break;
560 if (len < 0)
561 return len;
563 avp = NULL;
564 avplen = 0;
566 ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen);
567 if (ret < 0)
569 int tmpret;
570 tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL,
571 GNUTLS_A_INNER_APPLICATION_FAILURE);
572 if (tmpret < 0)
573 gnutls_assert ();
574 return ret;
577 msg_type = ret;
579 if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD)
581 ret = gnutls_ia_endphase_send (session, msg_type ==
582 GNUTLS_IA_FINAL_PHASE_FINISHED);
583 if (ret < 0)
584 return ret;
586 else
588 len = gnutls_ia_send (session, avp, avplen);
589 gnutls_free (avp);
590 if (len < 0)
591 return len;
594 while (1);
596 return 0;
600 * gnutls_ia_handshake_p:
601 * @session: is a #gnutls_session_t structure.
603 * Predicate to be used after gnutls_handshake() to decide whether to
604 * invoke gnutls_ia_handshake(). Usable by both clients and servers.
606 * Return value: non-zero if TLS/IA handshake is expected, zero
607 * otherwise.
610 gnutls_ia_handshake_p (gnutls_session_t session)
612 tls_ext_st *ext = &session->security_parameters.extensions;
614 /* Either local side or peer doesn't do TLS/IA: don't do IA */
616 if (!ext->gnutls_ia_enable || !ext->gnutls_ia_peer_enable)
617 return 0;
619 /* Not resuming or we don't allow skipping on resumption locally: do IA */
621 if (!ext->gnutls_ia_allowskip || !gnutls_session_is_resumed (session))
622 return 1;
624 /* If we're resuming and we and the peer both allow skipping on resumption:
625 * don't do IA */
627 return !ext->gnutls_ia_peer_allowskip;
632 * gnutls_ia_handshake:
633 * @session: is a #gnutls_session_t structure.
635 * Perform a TLS/IA handshake. This should be called after
636 * gnutls_handshake() iff gnutls_ia_handshake_p().
638 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
639 * otherwise an error code is returned.
642 gnutls_ia_handshake (gnutls_session_t session)
644 int ret;
646 if (session->security_parameters.entity == GNUTLS_CLIENT)
647 ret = _gnutls_ia_client_handshake (session);
648 else
649 ret = _gnutls_ia_server_handshake (session);
651 return ret;
655 * gnutls_ia_allocate_client_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
656 * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
658 * This structure is complex enough to manipulate directly thus this
659 * helper function is provided in order to allocate it.
661 * Adding this credential to a session will enable TLS/IA, and will
662 * require an Application Phase after the TLS handshake (if the server
663 * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
664 * TLS/IA mode.
666 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
667 * an error code is returned.
670 gnutls_ia_allocate_client_credentials (gnutls_ia_client_credentials_t * sc)
672 *sc = gnutls_calloc (1, sizeof (**sc));
674 if (*sc == NULL)
675 return GNUTLS_E_MEMORY_ERROR;
677 return 0;
681 * gnutls_ia_free_client_credentials - Used to free an allocated #gnutls_ia_client_credentials_t structure
682 * @sc: is a #gnutls_ia_client_credentials_t structure.
684 * This structure is complex enough to manipulate directly thus this
685 * helper function is provided in order to free (deallocate) it.
688 void
689 gnutls_ia_free_client_credentials (gnutls_ia_client_credentials_t sc)
691 gnutls_free (sc);
695 * gnutls_ia_set_client_avp_function - Used to set a AVP callback
696 * @cred: is a #gnutls_ia_client_credentials_t structure.
697 * @avp_func: is the callback function
699 * Set the TLS/IA AVP callback handler used for the session.
701 * The AVP callback is called to process AVPs received from the
702 * server, and to get a new AVP to send to the server.
704 * The callback's function form is:
705 * int (*avp_func) (gnutls_session_t session, void *ptr,
706 * const char *last, size_t lastlen,
707 * char **next, size_t *nextlen);
709 * The @session parameter is the #gnutls_session_t structure
710 * corresponding to the current session. The @ptr parameter is the
711 * application hook pointer, set through
712 * gnutls_ia_set_client_avp_ptr(). The AVP received from the server
713 * is present in @last of @lastlen size, which will be %NULL on the
714 * first invocation. The newly allocated output AVP to send to the
715 * server should be placed in *@next of *@nextlen size.
717 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
718 * generated session keys with the TLS/IA inner secret.
720 * Return 0 (%GNUTLS_IA_APPLICATION_PAYLOAD) on success, or a negative
721 * error code to abort the TLS/IA handshake.
723 * Note that the callback must use allocate the @next parameter using
724 * gnutls_malloc(), because it is released via gnutls_free() by the
725 * TLS/IA handshake function.
728 void
729 gnutls_ia_set_client_avp_function (gnutls_ia_client_credentials_t cred,
730 gnutls_ia_avp_func avp_func)
732 cred->avp_func = avp_func;
736 * gnutls_ia_set_client_avp_ptr - Sets a pointer to be sent to TLS/IA callback
737 * @cred: is a #gnutls_ia_client_credentials_t structure.
738 * @ptr: is the pointer
740 * Sets the pointer that will be provided to the TLS/IA callback
741 * function as the first argument.
743 void
744 gnutls_ia_set_client_avp_ptr (gnutls_ia_client_credentials_t cred, void *ptr)
746 cred->avp_ptr = ptr;
750 * gnutls_ia_get_client_avp_ptr - Returns the pointer which is sent to TLS/IA callback
751 * @cred: is a #gnutls_ia_client_credentials_t structure.
753 * Returns the pointer that will be provided to the TLS/IA callback
754 * function as the first argument.
756 * Returns: The client callback data pointer.
758 void *
759 gnutls_ia_get_client_avp_ptr (gnutls_ia_client_credentials_t cred)
761 return cred->avp_ptr;
765 * gnutls_ia_allocate_server_credentials - Used to allocate an gnutls_ia_server_credentials_t structure
766 * @sc: is a pointer to a #gnutls_ia_server_credentials_t structure.
768 * This structure is complex enough to manipulate directly thus this
769 * helper function is provided in order to allocate it.
771 * Adding this credential to a session will enable TLS/IA, and will
772 * require an Application Phase after the TLS handshake (if the client
773 * support TLS/IA). Use gnutls_ia_require_inner_phase() to toggle the
774 * TLS/IA mode.
776 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
777 * an error code is returned.
780 gnutls_ia_allocate_server_credentials (gnutls_ia_server_credentials_t * sc)
782 *sc = gnutls_calloc (1, sizeof (**sc));
784 if (*sc == NULL)
785 return GNUTLS_E_MEMORY_ERROR;
787 return 0;
791 * gnutls_ia_free_server_credentials - Used to free an allocated #gnutls_ia_server_credentials_t structure
792 * @sc: is a #gnutls_ia_server_credentials_t structure.
794 * This structure is complex enough to manipulate directly thus this
795 * helper function is provided in order to free (deallocate) it.
798 void
799 gnutls_ia_free_server_credentials (gnutls_ia_server_credentials_t sc)
801 gnutls_free (sc);
805 * gnutls_ia_set_server_credentials_function - Used to set a AVP callback
806 * @cred: is a #gnutls_ia_server_credentials_t structure.
807 * @func: is the callback function
809 * Set the TLS/IA AVP callback handler used for the session.
811 * The callback's function form is:
812 * int (*avp_func) (gnutls_session_t session, void *ptr,
813 * const char *last, size_t lastlen,
814 * char **next, size_t *nextlen);
816 * The @session parameter is the #gnutls_session_t structure
817 * corresponding to the current session. The @ptr parameter is the
818 * application hook pointer, set through
819 * gnutls_ia_set_server_avp_ptr(). The AVP received from the client
820 * is present in @last of @lastlen size. The newly allocated output
821 * AVP to send to the client should be placed in *@next of *@nextlen
822 * size.
824 * The AVP callback is called to process incoming AVPs from the
825 * client, and to get a new AVP to send to the client. It can also be
826 * used to instruct the TLS/IA handshake to do go into the
827 * Intermediate or Final phases. It return a negative error code, or
828 * a #gnutls_ia_apptype_t message type.
830 * The callback may invoke gnutls_ia_permute_inner_secret() to mix any
831 * generated session keys with the TLS/IA inner secret.
833 * Specifically, return %GNUTLS_IA_APPLICATION_PAYLOAD (0) to send
834 * another AVP to the client, return
835 * %GNUTLS_IA_INTERMEDIATE_PHASE_FINISHED (1) to indicate that an
836 * IntermediatePhaseFinished message should be sent, and return
837 * %GNUTLS_IA_FINAL_PHASE_FINISHED (2) to indicate that an
838 * FinalPhaseFinished message should be sent. In the last two cases,
839 * the contents of the @next and @nextlen parameter is not used.
841 * Note that the callback must use allocate the @next parameter using
842 * gnutls_malloc(), because it is released via gnutls_free() by the
843 * TLS/IA handshake function.
845 void
846 gnutls_ia_set_server_avp_function (gnutls_ia_server_credentials_t cred,
847 gnutls_ia_avp_func avp_func)
849 cred->avp_func = avp_func;
853 * gnutls_ia_set_server_avp_ptr - Sets a pointer to be sent to TLS/IA callback
854 * @cred: is a #gnutls_ia_client_credentials_t structure.
855 * @ptr: is the pointer
857 * Sets the pointer that will be provided to the TLS/IA callback
858 * function as the first argument.
860 void
861 gnutls_ia_set_server_avp_ptr (gnutls_ia_server_credentials_t cred, void *ptr)
863 cred->avp_ptr = ptr;
867 * gnutls_ia_get_server_avp_ptr - Returns the pointer which is sent to TLS/IA callback
868 * @cred: is a #gnutls_ia_client_credentials_t structure.
870 * Returns the pointer that will be provided to the TLS/IA callback
871 * function as the first argument.
873 * Returns: The server callback data pointer.
875 void *
876 gnutls_ia_get_server_avp_ptr (gnutls_ia_server_credentials_t cred)
878 return cred->avp_ptr;
882 * gnutls_ia_enable - Indicate willingness for TLS/IA application phases
883 * @session: is a #gnutls_session_t structure.
884 * @allow_skip_on_resume: non-zero if local party allows to skip the
885 * TLS/IA application phases for a resumed session.
887 * Specify whether we must advertise support for the TLS/IA extension
888 * during the handshake.
890 * At the client side, we always advertise TLS/IA if gnutls_ia_enable
891 * was called before the handshake; at the server side, we also
892 * require that the client has advertised that it wants to run TLS/IA
893 * before including the advertisement, as required by the protocol.
895 * Similarly, at the client side we always advertise that we allow
896 * TLS/IA to be skipped for resumed sessions if @allow_skip_on_resume
897 * is non-zero; at the server side, we also require that the session
898 * is indeed resumable and that the client has also advertised that it
899 * allows TLS/IA to be skipped for resumed sessions.
901 * After the TLS handshake, call gnutls_ia_handshake_p() to find out
902 * whether both parties agreed to do a TLS/IA handshake, before
903 * calling gnutls_ia_handshake() or one of the lower level gnutls_ia_*
904 * functions.
906 void
907 gnutls_ia_enable (gnutls_session_t session, int allow_skip_on_resume)
909 session->security_parameters.extensions.gnutls_ia_enable = 1;
910 session->security_parameters.extensions.gnutls_ia_allowskip =
911 allow_skip_on_resume;