Callback revision.
[openssl.git] / ssl / t1_ext.c
1 /* ssl/t1_ext.c */
2 /* ====================================================================
3  * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    openssl-core@openssl.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55
56 /* Custom extension utility functions */
57
58 #include "ssl_locl.h"
59
60 #ifndef OPENSSL_NO_TLSEXT
61
62 /* Find a custom extension from the list */
63
64 static custom_ext_method *custom_ext_find(custom_ext_methods *exts,
65                                                 unsigned short ext_type)
66         {
67         size_t i;
68         custom_ext_method *meth = exts->meths;
69         for (i = 0; i < exts->meths_count; i++, meth++)
70                 {
71                 if (ext_type == meth->ext_type)
72                         return meth;
73                 }
74         return NULL;
75         }
76 /* Initialise custom extensions flags to indicate neither sent nor
77  * received.
78  */
79 void custom_ext_init(custom_ext_methods *exts)
80         {
81         size_t i;
82         custom_ext_method *meth = exts->meths;
83         for (i = 0; i < exts->meths_count; i++, meth++)
84                 meth->ext_flags = 0;
85         }
86
87 /* pass received custom extension data to the application for parsing */
88
89 int custom_ext_parse(SSL *s, int server,
90                         unsigned int ext_type,
91                         const unsigned char *ext_data, 
92                         size_t ext_size,
93                         int *al)
94         {
95         custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
96         custom_ext_method *meth;
97         meth = custom_ext_find(exts, ext_type);
98         /* If not found or no parse function set, return success */
99         /* If not found return success */
100         if (!meth)
101                 return 1;
102         if (!server)
103                 {
104                 /* If it's ServerHello we can't have any extensions not 
105                  * sent in ClientHello.
106                  */
107                 if (!(meth->ext_flags & SSL_EXT_FLAG_SENT))
108                         {
109                         *al = TLS1_AD_UNSUPPORTED_EXTENSION;
110                         return 0;
111                         }
112                 }
113         /* If already present it's a duplicate */
114         if (meth->ext_flags & SSL_EXT_FLAG_RECEIVED)
115                 {
116                 *al = TLS1_AD_DECODE_ERROR;
117                 return 0;
118                 }
119         meth->ext_flags |= SSL_EXT_FLAG_RECEIVED;
120         if (!meth->parse_cb)
121                 return 1;
122
123         return meth->parse_cb(s, ext_type, ext_data, ext_size, al, meth->arg);
124         }
125
126 /* request custom extension data from the application and add to the
127  * return buffer
128  */
129
130 int custom_ext_add(SSL *s, int server,
131                         unsigned char **pret,
132                         unsigned char *limit,
133                         int *al)
134         {
135         custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
136         custom_ext_method *meth;
137         unsigned char *ret = *pret;
138         size_t i;
139
140         for (i = 0; i < exts->meths_count; i++)
141                 {
142                 const unsigned char *out = NULL;
143                 size_t outlen = 0;
144                 meth = exts->meths + i;
145
146                 if (server)
147                         {
148                         /* For ServerHello only send extensions present
149                          * in ClientHello.
150                          */
151                         if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED))
152                                 continue;
153                         /* If callback absent for server skip it */
154                         if (!meth->add_cb)
155                                 continue;
156                         }
157                 if (meth->add_cb)
158                         {
159                         int cb_retval = 0;
160                         cb_retval = meth->add_cb(s, meth->ext_type,
161                                                         &out, &outlen, al,
162                                                         meth->arg);
163                         if (cb_retval == 0)
164                                 return 0; /* error */
165                         if (cb_retval == -1)
166                                         continue; /* skip this extension */
167                         }
168                 if (4 > limit - ret || outlen > (size_t)(limit - ret - 4))
169                         return 0;
170                 s2n(meth->ext_type, ret);
171                 s2n(outlen, ret);
172                 if (outlen)
173                         {
174                         memcpy(ret, out, outlen);
175                         ret += outlen;
176                         }
177                 /* We can't send duplicates: code logic should prevent this */
178                 OPENSSL_assert(!(meth->ext_flags & SSL_EXT_FLAG_SENT));
179                 /* Indicate extension has been sent: this is both a sanity
180                  * check to ensure we don't send duplicate extensions
181                  * and indicates to servers that an extension can be
182                  * sent in ServerHello.
183                  */
184                 meth->ext_flags |= SSL_EXT_FLAG_SENT;
185                 }
186         *pret = ret;
187         return 1;
188         }
189
190 /* Copy table of custom extensions */
191
192 int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
193         {
194         if (src->meths_count)
195                 {
196                 dst->meths = BUF_memdup(src->meths, sizeof(custom_ext_method) * src->meths_count);
197                 if (dst->meths == NULL)
198                         return 0;
199                 dst->meths_count = src->meths_count;
200                 }
201         return 1;
202         }
203
204 void custom_exts_free(custom_ext_methods *exts)
205         {
206         if (exts->meths)
207                 OPENSSL_free(exts->meths);
208         }
209
210 /* Set callbacks for a custom extension */
211 static int custom_ext_set(custom_ext_methods *exts,
212                         unsigned int ext_type,
213                         custom_ext_parse_cb parse_cb,
214                         custom_ext_add_cb add_cb,
215                         void *arg)
216         {
217         custom_ext_method *meth;
218         /* See if it is a supported internally */
219         switch(ext_type)
220                 {
221         case TLSEXT_TYPE_application_layer_protocol_negotiation:
222         case TLSEXT_TYPE_ec_point_formats:
223         case TLSEXT_TYPE_elliptic_curves:
224         case TLSEXT_TYPE_heartbeat:
225         case TLSEXT_TYPE_next_proto_neg:
226         case TLSEXT_TYPE_padding:
227         case TLSEXT_TYPE_renegotiate:
228         case TLSEXT_TYPE_server_name:
229         case TLSEXT_TYPE_session_ticket:
230         case TLSEXT_TYPE_signature_algorithms:
231         case TLSEXT_TYPE_srp:
232         case TLSEXT_TYPE_status_request:
233         case TLSEXT_TYPE_use_srtp:
234 #ifdef TLSEXT_TYPE_opaque_prf_input
235         case TLSEXT_TYPE_opaque_prf_input:
236 #endif
237 #ifdef TLSEXT_TYPE_encrypt_then_mac
238         case TLSEXT_TYPE_encrypt_then_mac:
239 #endif
240                 return 0;
241                 }
242         /* Extension type must fit in 16 bits */
243         if (ext_type > 0xffff)
244                 return 0;
245         /* Search for duplicate */
246         if (custom_ext_find(exts, ext_type))
247                 return 0;
248         exts->meths = OPENSSL_realloc(exts->meths,
249                                         (exts->meths_count + 1) * sizeof(custom_ext_method));
250
251         if (!exts->meths)
252                 {
253                 exts->meths_count = 0;
254                 return 0;
255                 }
256
257         meth = exts->meths + exts->meths_count;
258         memset(meth, 0, sizeof(custom_ext_method));
259         meth->parse_cb = parse_cb;
260         meth->add_cb = add_cb;
261         meth->ext_type = ext_type;
262         meth->arg = arg;
263         exts->meths_count++;
264         return 1;
265         }
266
267 /* Application level functions to add custom extension callbacks */
268
269 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned int ext_type,
270                                custom_ext_add_cb add_cb, 
271                                custom_ext_parse_cb parse_cb, void *arg)
272
273         {
274         return custom_ext_set(&ctx->cert->cli_ext, ext_type, parse_cb, add_cb,
275                                                                         arg);
276         }
277
278 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned int ext_type,
279                                custom_ext_parse_cb parse_cb, 
280                                custom_ext_add_cb add_cb, void *arg)
281         {
282         return custom_ext_set(&ctx->cert->srv_ext, ext_type, parse_cb, add_cb,
283                                                                         arg);
284         }
285 #endif