2 * Copyright (C) 2005, 2006, 2008, 2010 Free Software Foundation, Inc.
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 3 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 this program. If not, see
20 * <http://www.gnu.org/licenses/>.
24 #include "gnutls_int.h"
25 #include "gnutls_auth.h"
26 #include "gnutls_errors.h"
27 #include "gnutls_num.h"
28 #include "ext_inner_application.h"
29 #include <gnutls/extra.h>
34 static int _gnutls_inner_application_recv_params (gnutls_session_t session
,
37 static int _gnutls_inner_application_send_params (gnutls_session_t session
,
38 opaque
* data
, size_t);
39 static int ia_unpack (gnutls_buffer_st
* ps
, extension_priv_data_t
* _priv
);
40 static int ia_pack (extension_priv_data_t _priv
, gnutls_buffer_st
* ps
);
41 static void ia_deinit_data (extension_priv_data_t priv
);
43 extension_entry_st ext_mod_ia
= {
44 .name
= "INNER APPLICATION",
45 .type
= GNUTLS_EXTENSION_INNER_APPLICATION
,
46 .parse_type
= GNUTLS_EXT_TLS
,
48 .recv_func
= _gnutls_inner_application_recv_params
,
49 .send_func
= _gnutls_inner_application_send_params
,
51 .unpack_func
= ia_unpack
,
52 .deinit_func
= ia_deinit_data
,
56 _gnutls_inner_application_recv_params (gnutls_session_t session
,
57 const opaque
* data
, size_t data_size
)
59 extension_priv_data_t epriv
;
66 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH
;
70 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_INNER_APPLICATION
,
74 priv
= gnutls_calloc (1, sizeof (*priv
));
78 return GNUTLS_E_MEMORY_ERROR
;
82 _gnutls_ext_set_session_data (session
,
83 GNUTLS_EXTENSION_INNER_APPLICATION
,
89 priv
->flags
|= IA_PEER_ENABLE
;
90 priv
->flags
&= ~IA_PEER_ALLOW_SKIP
;
92 switch ((unsigned char) *data
)
94 case NO
: /* Peer's ia_on_resume == no */
95 priv
->flags
|= IA_PEER_ALLOW_SKIP
;
110 /* returns data_size or a negative number on failure
113 _gnutls_inner_application_send_params (gnutls_session_t session
,
114 opaque
* data
, size_t data_size
)
116 extension_priv_data_t epriv
;
117 ia_ext_st
*priv
= NULL
;
121 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_INNER_APPLICATION
,
125 priv
= gnutls_calloc (1, sizeof (*priv
));
129 return GNUTLS_E_MEMORY_ERROR
;
133 _gnutls_ext_set_session_data (session
,
134 GNUTLS_EXTENSION_INNER_APPLICATION
,
140 /* Set ext->gnutls_ia_enable depending on whether we have a TLS/IA
141 credential in the session. */
143 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
145 gnutls_ia_client_credentials_t cred
= (gnutls_ia_client_credentials_t
)
146 _gnutls_get_cred (session
->key
, GNUTLS_CRD_IA
, NULL
);
149 priv
->flags
|= IA_ENABLE
;
153 gnutls_ia_server_credentials_t cred
;
155 cred
= (gnutls_ia_server_credentials_t
)
156 _gnutls_get_cred (session
->key
, GNUTLS_CRD_IA
, NULL
);
159 priv
->flags
|= IA_PEER_ENABLE
;
162 /* If we don't want gnutls_ia locally, or we are a server and the
163 * client doesn't want it, don't advertise TLS/IA support at all, as
166 if (!(priv
->flags
& IA_ENABLE
))
169 if (session
->security_parameters
.entity
== GNUTLS_SERVER
&&
170 !(priv
->flags
& IA_PEER_ENABLE
))
173 /* We'll advertise. Check if there's room in the hello buffer. */
178 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
181 /* default: require new application phase */
185 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
188 /* Client: value follows local setting */
190 if (priv
->flags
& IA_ALLOW_SKIP
)
196 /* Server: value follows local setting and client's setting, but only
197 * if we are resuming.
199 * XXX Can server test for resumption at this stage?
201 * Ai! It seems that read_client_hello only calls parse_extensions if
202 * we're NOT resuming! That would make us automatically violate the IA
203 * draft; if we're resuming, we must first learn what the client wants
204 * -- IA or no IA -- and then prepare our response. Right now we'll
205 * always skip IA on resumption, because recv_ext isn't even called
206 * to record the peer's support for IA at all. Simon? */
208 if ((priv
->flags
& IA_ALLOW_SKIP
) &&
209 (priv
->flags
& IA_PEER_ALLOW_SKIP
) &&
210 session
->internals
.resumed
== RESUME_TRUE
)
218 ia_deinit_data (extension_priv_data_t priv
)
220 gnutls_free (priv
.ptr
);
224 ia_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
226 ia_ext_st
*priv
= epriv
.ptr
;
229 BUFFER_APPEND_NUM (ps
, priv
->flags
);
230 BUFFER_APPEND_PFX (ps
, priv
->inner_secret
, GNUTLS_MASTER_SIZE
);
236 ia_unpack (gnutls_buffer_st
* ps
, extension_priv_data_t
* _priv
)
240 extension_priv_data_t epriv
;
242 priv
= gnutls_calloc (1, sizeof (*priv
));
246 return GNUTLS_E_MEMORY_ERROR
;
249 BUFFER_POP_NUM (ps
, priv
->flags
);
250 BUFFER_POP_NUM (ps
, size
);
251 if (size
!= GNUTLS_MASTER_SIZE
)
254 return GNUTLS_E_PARSING_ERROR
;
256 BUFFER_POP (ps
, priv
->inner_secret
, GNUTLS_MASTER_SIZE
);