~ubuntu-branches/ubuntu/wily/weechat/wily

« back to all changes in this revision

Viewing changes to src/plugins/irc/irc-sasl.c

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bouthenot
  • Date: 2015-08-19 18:34:17 UTC
  • mfrom: (29.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20150819183417-u026z5wo8knpcdqd
Tags: 1.3-1
* New upstream release
  - Remove backported patch to fix FTBFS with ruby 2.2
* Use dh-exec to build javascript plugin only on architectures which v8
  engine supports. Thanks to Mateusz Łukasik for the patch
  (Closes: #794584)

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <arpa/inet.h>
26
26
#include <gcrypt.h>
27
27
 
 
28
#ifdef HAVE_GNUTLS
 
29
#include <gnutls/gnutls.h>
 
30
#if LIBGNUTLS_VERSION_NUMBER >= 0x020a01 /* 2.10.1 */
 
31
#include <gnutls/abstract.h>
 
32
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020a01 */
 
33
#endif /* HAVE_GNUTLS */
 
34
 
28
35
#include "../weechat-plugin.h"
29
36
#include "irc.h"
30
37
#include "irc-sasl.h"
31
 
 
32
 
 
 
38
#include "irc-server.h"
 
39
 
 
40
 
 
41
/*
 
42
 * these names are sent to the IRC server (as upper case), so they must be
 
43
 * valid values for the AUTHENTICATE command (example: "AUTHENTICATE PLAIN")
 
44
 */
33
45
char *irc_sasl_mechanism_string[IRC_NUM_SASL_MECHANISMS] =
34
 
{ "plain", "dh-blowfish", "dh-aes", "external" };
 
46
{ "plain", "ecdsa-nist256p-challenge", "external", "dh-blowfish", "dh-aes" };
35
47
 
36
48
 
37
49
/*
68
80
}
69
81
 
70
82
/*
 
83
 * Returns the content of file with SASL key.
 
84
 *
 
85
 * Note: result must be freed after use.
 
86
 */
 
87
 
 
88
char *
 
89
irc_sasl_get_key_content (struct t_irc_server *server, const char *sasl_key)
 
90
{
 
91
    const char *weechat_dir;
 
92
    char *key_path1, *key_path2, *content;
 
93
 
 
94
    if (!sasl_key)
 
95
        return NULL;
 
96
 
 
97
    content = NULL;
 
98
 
 
99
    weechat_dir = weechat_info_get ("weechat_dir", "");
 
100
    key_path1 = weechat_string_replace (sasl_key, "%h", weechat_dir);
 
101
    key_path2 = (key_path1) ?
 
102
        weechat_string_expand_home (key_path1) : NULL;
 
103
 
 
104
    if (key_path2)
 
105
        content = weechat_file_get_content (key_path2);
 
106
 
 
107
    if (!content)
 
108
    {
 
109
        weechat_printf (
 
110
            server->buffer,
 
111
            _("%s%s: unable to read private key in file \"%s\""),
 
112
            weechat_prefix ("error"),
 
113
            IRC_PLUGIN_NAME,
 
114
            (key_path2) ? key_path2 : ((key_path1) ? key_path1 : sasl_key));
 
115
    }
 
116
 
 
117
    if (key_path1)
 
118
        free (key_path1);
 
119
    if (key_path2)
 
120
        free (key_path2);
 
121
 
 
122
    return content;
 
123
}
 
124
 
 
125
/*
 
126
 * Builds answer for SASL authentication, using mechanism
 
127
 * "ECDSA-NIST256P-CHALLENGE".
 
128
 *
 
129
 * Note: result must be freed after use.
 
130
 */
 
131
 
 
132
char *
 
133
irc_sasl_mechanism_ecdsa_nist256p_challenge (struct t_irc_server *server,
 
134
                                             const char *data_base64,
 
135
                                             const char *sasl_username,
 
136
                                             const char *sasl_key)
 
137
{
 
138
#if defined(HAVE_GNUTLS) && (LIBGNUTLS_VERSION_NUMBER >= 0x030015) /* 3.0.21 */
 
139
    char *data, *string, *answer_base64;
 
140
    int length_data, length_username, length, ret;
 
141
    char *str_privkey;
 
142
    gnutls_x509_privkey_t x509_privkey;
 
143
    gnutls_privkey_t privkey;
 
144
    gnutls_datum_t filedatum, decoded_data, signature;
 
145
#if LIBGNUTLS_VERSION_NUMBER >= 0x030300 /* 3.3.0 */
 
146
    gnutls_ecc_curve_t curve;
 
147
    gnutls_datum_t x, y, k;
 
148
    char *pubkey, *pubkey_base64;
 
149
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x030300 */
 
150
 
 
151
    answer_base64 = NULL;
 
152
    string = NULL;
 
153
    length = 0;
 
154
 
 
155
    if (strcmp (data_base64, "+") == 0)
 
156
    {
 
157
        /* send "username" + '\0' + "username" */
 
158
        answer_base64 = NULL;
 
159
        length_username = strlen (sasl_username);
 
160
        length = length_username + 1 + length_username;
 
161
        string = malloc (length + 1);
 
162
        if (string)
 
163
        {
 
164
            snprintf (string, length + 1, "%s|%s", sasl_username, sasl_username);
 
165
            string[length_username] = '\0';
 
166
        }
 
167
    }
 
168
    else
 
169
    {
 
170
        /* sign the challenge with the private key and return the result */
 
171
 
 
172
        /* decode the challenge */
 
173
        data = malloc (strlen (data_base64) + 1);
 
174
        if (!data)
 
175
            return NULL;
 
176
        length_data = weechat_string_decode_base64 (data_base64, data);
 
177
 
 
178
        /* read file with private key */
 
179
        str_privkey = irc_sasl_get_key_content (server, sasl_key);
 
180
        if (!str_privkey)
 
181
        {
 
182
            free (data);
 
183
            return NULL;
 
184
        }
 
185
 
 
186
        /* import key */
 
187
        gnutls_x509_privkey_init (&x509_privkey);
 
188
        gnutls_privkey_init (&privkey);
 
189
        filedatum.data = (unsigned char *)str_privkey;
 
190
        filedatum.size = strlen (str_privkey);
 
191
        ret = gnutls_x509_privkey_import (x509_privkey, &filedatum,
 
192
                                          GNUTLS_X509_FMT_PEM);
 
193
        free (str_privkey);
 
194
        if (ret != GNUTLS_E_SUCCESS)
 
195
        {
 
196
            weechat_printf (
 
197
                server->buffer,
 
198
                _("%sgnutls: invalid private key file: error %d %s"),
 
199
                weechat_prefix ("error"),
 
200
                ret,
 
201
                gnutls_strerror (ret));
 
202
            gnutls_x509_privkey_deinit (x509_privkey);
 
203
            gnutls_privkey_deinit (privkey);
 
204
            free (data);
 
205
            return NULL;
 
206
        }
 
207
 
 
208
#if LIBGNUTLS_VERSION_NUMBER >= 0x030300 /* 3.3.0 */
 
209
        /* read raw values in key, to display public key */
 
210
        ret = gnutls_x509_privkey_export_ecc_raw (x509_privkey,
 
211
                                                  &curve, &x, &y, &k);
 
212
        if (ret == GNUTLS_E_SUCCESS)
 
213
        {
 
214
            pubkey = malloc (x.size + 1);
 
215
            if (pubkey)
 
216
            {
 
217
                pubkey[0] = (y.data[y.size - 1] & 1) ? 0x03 : 0x02;
 
218
                memcpy (pubkey + 1, x.data, x.size);
 
219
                pubkey_base64 = malloc ((x.size + 1 + 1) * 4);
 
220
                if (pubkey_base64)
 
221
                {
 
222
                    weechat_string_encode_base64 (pubkey, x.size + 1,
 
223
                                                  pubkey_base64);
 
224
                    weechat_printf (
 
225
                        server->buffer,
 
226
                        _("%s%s: signing the challenge with ECC public key: "
 
227
                          "%s"),
 
228
                        weechat_prefix ("network"),
 
229
                        IRC_PLUGIN_NAME,
 
230
                        pubkey_base64);
 
231
                    free (pubkey_base64);
 
232
                }
 
233
                free (pubkey);
 
234
            }
 
235
            gnutls_free (x.data);
 
236
            gnutls_free (y.data);
 
237
            gnutls_free (k.data);
 
238
        }
 
239
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x030300 */
 
240
 
 
241
        /* import private key in an abstract key structure */
 
242
        ret = gnutls_privkey_import_x509 (privkey, x509_privkey, 0); /* gnutls >= 2.11.0 */
 
243
        if (ret != GNUTLS_E_SUCCESS)
 
244
        {
 
245
            weechat_printf (
 
246
                server->buffer,
 
247
                _("%sgnutls: unable to import the private key: error %d %s"),
 
248
                weechat_prefix ("error"),
 
249
                ret,
 
250
                gnutls_strerror (ret));
 
251
            gnutls_x509_privkey_deinit (x509_privkey);
 
252
            gnutls_privkey_deinit (privkey);
 
253
            free (data);
 
254
            return NULL;
 
255
        }
 
256
 
 
257
        decoded_data.data = (unsigned char *)data;
 
258
        decoded_data.size = length_data;
 
259
        ret = gnutls_privkey_sign_hash (privkey, GNUTLS_DIG_SHA256, 0, /* gnutls >= 2.11.0 */
 
260
                                        &decoded_data, &signature);
 
261
        if (ret != GNUTLS_E_SUCCESS)
 
262
        {
 
263
            weechat_printf (
 
264
                server->buffer,
 
265
                _("%sgnutls: unable to sign the hashed data: error %d %s"),
 
266
                weechat_prefix ("error"),
 
267
                ret,
 
268
                gnutls_strerror (ret));
 
269
            gnutls_x509_privkey_deinit (x509_privkey);
 
270
            gnutls_privkey_deinit (privkey);
 
271
            free (data);
 
272
            return NULL;
 
273
        }
 
274
 
 
275
        gnutls_x509_privkey_deinit (x509_privkey);
 
276
        gnutls_privkey_deinit (privkey);
 
277
 
 
278
        string = malloc (signature.size);
 
279
        if (string)
 
280
            memcpy (string, signature.data, signature.size);
 
281
        length = signature.size;
 
282
 
 
283
        gnutls_free (signature.data);
 
284
 
 
285
        free (data);
 
286
    }
 
287
 
 
288
    if (string && (length > 0))
 
289
    {
 
290
        answer_base64 = malloc ((length + 1) * 4);
 
291
        if (answer_base64)
 
292
            weechat_string_encode_base64 (string, length, answer_base64);
 
293
        free (string);
 
294
    }
 
295
 
 
296
    return answer_base64;
 
297
 
 
298
#else /* no gnutls or gnutls < 3.0.21 */
 
299
 
 
300
    /* make C compiler happy */
 
301
    (void) data_base64;
 
302
    (void) sasl_username;
 
303
    (void) sasl_key;
 
304
 
 
305
    weechat_printf (server->buffer,
 
306
                    _("%sgnutls: version >= 3.0.21 is required for SASL "
 
307
                      "\"ecdsa-nist256p-challenge\""),
 
308
                    weechat_prefix ("error"));
 
309
 
 
310
    return NULL;
 
311
#endif /* defined(HAVE_GNUTLS) && (LIBGNUTLS_VERSION_NUMBER >= 0x030015) */
 
312
}
 
313
 
 
314
/*
71
315
 * Reads key sent by server (Diffie-Hellman key exchange).
72
316
 *
73
317
 * Returns:
186
430
 *
187
431
 * Note: result must be freed after use.
188
432
 */
 
433
 
189
434
char *
190
435
irc_sasl_mechanism_dh_blowfish (const char *data_base64,
191
436
                                const char *sasl_username,
249
494
    memcpy (ptr_answer, password_crypted, length_password);
250
495
 
251
496
    /* encode answer to base64 */
252
 
    answer_base64 = malloc (length_answer * 4);
 
497
    answer_base64 = malloc ((length_answer + 1) * 4);
253
498
    if (answer_base64)
254
499
        weechat_string_encode_base64 (answer, length_answer, answer_base64);
255
500
 
279
524
 *
280
525
 * Note: result must be freed after use.
281
526
 */
 
527
 
282
528
char *
283
529
irc_sasl_mechanism_dh_aes (const char *data_base64,
284
530
                           const char *sasl_username,
370
616
    memcpy (ptr_answer, userpass_crypted, length_userpass);
371
617
 
372
618
    /* encode answer to base64 */
373
 
    answer_base64 = malloc (length_answer * 4);
 
619
    answer_base64 = malloc ((length_answer + 1) * 4);
374
620
    if (answer_base64)
375
621
        weechat_string_encode_base64 (answer, length_answer, answer_base64);
376
622