83
* Returns the content of file with SASL key.
85
* Note: result must be freed after use.
89
irc_sasl_get_key_content (struct t_irc_server *server, const char *sasl_key)
91
const char *weechat_dir;
92
char *key_path1, *key_path2, *content;
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;
105
content = weechat_file_get_content (key_path2);
111
_("%s%s: unable to read private key in file \"%s\""),
112
weechat_prefix ("error"),
114
(key_path2) ? key_path2 : ((key_path1) ? key_path1 : sasl_key));
126
* Builds answer for SASL authentication, using mechanism
127
* "ECDSA-NIST256P-CHALLENGE".
129
* Note: result must be freed after use.
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)
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;
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 */
151
answer_base64 = NULL;
155
if (strcmp (data_base64, "+") == 0)
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);
164
snprintf (string, length + 1, "%s|%s", sasl_username, sasl_username);
165
string[length_username] = '\0';
170
/* sign the challenge with the private key and return the result */
172
/* decode the challenge */
173
data = malloc (strlen (data_base64) + 1);
176
length_data = weechat_string_decode_base64 (data_base64, data);
178
/* read file with private key */
179
str_privkey = irc_sasl_get_key_content (server, sasl_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);
194
if (ret != GNUTLS_E_SUCCESS)
198
_("%sgnutls: invalid private key file: error %d %s"),
199
weechat_prefix ("error"),
201
gnutls_strerror (ret));
202
gnutls_x509_privkey_deinit (x509_privkey);
203
gnutls_privkey_deinit (privkey);
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,
212
if (ret == GNUTLS_E_SUCCESS)
214
pubkey = malloc (x.size + 1);
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);
222
weechat_string_encode_base64 (pubkey, x.size + 1,
226
_("%s%s: signing the challenge with ECC public key: "
228
weechat_prefix ("network"),
231
free (pubkey_base64);
235
gnutls_free (x.data);
236
gnutls_free (y.data);
237
gnutls_free (k.data);
239
#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x030300 */
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)
247
_("%sgnutls: unable to import the private key: error %d %s"),
248
weechat_prefix ("error"),
250
gnutls_strerror (ret));
251
gnutls_x509_privkey_deinit (x509_privkey);
252
gnutls_privkey_deinit (privkey);
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)
265
_("%sgnutls: unable to sign the hashed data: error %d %s"),
266
weechat_prefix ("error"),
268
gnutls_strerror (ret));
269
gnutls_x509_privkey_deinit (x509_privkey);
270
gnutls_privkey_deinit (privkey);
275
gnutls_x509_privkey_deinit (x509_privkey);
276
gnutls_privkey_deinit (privkey);
278
string = malloc (signature.size);
280
memcpy (string, signature.data, signature.size);
281
length = signature.size;
283
gnutls_free (signature.data);
288
if (string && (length > 0))
290
answer_base64 = malloc ((length + 1) * 4);
292
weechat_string_encode_base64 (string, length, answer_base64);
296
return answer_base64;
298
#else /* no gnutls or gnutls < 3.0.21 */
300
/* make C compiler happy */
302
(void) sasl_username;
305
weechat_printf (server->buffer,
306
_("%sgnutls: version >= 3.0.21 is required for SASL "
307
"\"ecdsa-nist256p-challenge\""),
308
weechat_prefix ("error"));
311
#endif /* defined(HAVE_GNUTLS) && (LIBGNUTLS_VERSION_NUMBER >= 0x030015) */
71
315
* Reads key sent by server (Diffie-Hellman key exchange).