Custom extension 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
77 /* pass received custom extension data to the application for parsing */
78
79 int custom_ext_parse(SSL *s, int server,
80                         unsigned short ext_type,
81                         const unsigned char *ext_data, 
82                         unsigned short ext_size,
83                         int *al)
84         {
85         custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
86         custom_ext_method *meth;
87         meth = custom_ext_find(exts, ext_type);
88         /* If not found or no parse function set, return success */
89         if (!meth || !meth->parse_cb)
90                 return 1;
91
92         return meth->parse_cb(s, ext_type, ext_data, ext_size, al, meth->arg);
93         }
94
95 /* request custom extension data from the application and add to the
96  * return buffer
97  */
98
99 int custom_ext_add(SSL *s, int server,
100                         unsigned char **pret,
101                         unsigned char *limit,
102                         int *al)
103         {
104         custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext;
105         custom_ext_method *meth;
106         unsigned char *ret = *pret;
107         size_t i;
108
109         for (i = 0; i < exts->meths_count; i++)
110                 {
111                 const unsigned char *out = NULL;
112                 unsigned short outlen = 0;
113                 meth = exts->meths + i;
114
115                 /* For servers no callback omits extension,
116                  * For clients it sends empty extension.
117                  */
118                 if (server && !meth->add_cb)
119                         continue;
120                 if (meth->add_cb)
121                         {
122                         int cb_retval = 0;
123                         cb_retval = meth->add_cb(s, meth->ext_type,
124                                                         &out, &outlen, al,
125                                                         meth->arg);
126                         if (cb_retval == 0)
127                                 return 0; /* error */
128                         if (cb_retval == -1)
129                                         continue; /* skip this extension */
130                         }
131                 if (4 > limit - ret || outlen > limit - ret - 4)
132                         return 0;
133                 s2n(meth->ext_type, ret);
134                 s2n(outlen, ret);
135                 if (outlen)
136                         {
137                         memcpy(ret, out, outlen);
138                         ret += outlen;
139                         }
140                 }
141         *pret = ret;
142         return 1;
143         }
144
145 /* Copy table of custom extensions */
146
147 int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
148         {
149         if (src->meths_count)
150                 {
151                 dst->meths = BUF_memdup(src->meths, sizeof(custom_ext_method) * src->meths_count);
152                 if (dst->meths == NULL)
153                         return 0;
154                 dst->meths_count = src->meths_count;
155                 }
156         return 1;
157         }
158
159 void custom_exts_free(custom_ext_methods *exts)
160         {
161         if (exts->meths)
162                 OPENSSL_free(exts->meths);
163         }
164
165 /* Set callbacks for a custom extension */
166 static int custom_ext_set(custom_ext_methods *exts,
167                         unsigned short ext_type,
168                         custom_ext_parse_cb parse_cb,
169                         custom_ext_add_cb add_cb,
170                         void *arg)
171         {
172         custom_ext_method *meth;
173         /* Search for duplicate */
174         if (custom_ext_find(exts, ext_type))
175                 return 0;
176         exts->meths = OPENSSL_realloc(exts->meths,
177                                         (exts->meths_count + 1) * sizeof(custom_ext_method));
178
179         if (!exts->meths)
180                 {
181                 exts->meths_count = 0;
182                 return 0;
183                 }
184
185         meth = exts->meths + exts->meths_count;
186         meth->parse_cb = parse_cb;
187         meth->add_cb = add_cb;
188         meth->ext_type = ext_type;
189         meth->arg = arg;
190         exts->meths_count++;
191         return 1;
192         }
193
194 /* Application level functions to add custom extension callbacks */
195
196 int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
197                                custom_cli_ext_first_cb_fn fn1, 
198                                custom_cli_ext_second_cb_fn fn2, void *arg)
199         {
200         return custom_ext_set(&ctx->cert->cli_ext, ext_type, fn2, fn1, arg);
201         }
202
203 int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
204                                custom_srv_ext_first_cb_fn fn1, 
205                                custom_srv_ext_second_cb_fn fn2, void *arg)
206         {
207         return custom_ext_set(&ctx->cert->srv_ext, ext_type, fn1, fn2, arg);
208         }
209 #endif