~ubuntu-branches/ubuntu/saucy/wpasupplicant/saucy

« back to all changes in this revision

Viewing changes to src/crypto/tls_gnutls.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2010-11-22 09:43:43 UTC
  • mfrom: (1.1.16 upstream)
  • Revision ID: james.westby@ubuntu.com-20101122094343-qgsxaojvmswfri77
Tags: 0.7.3-0ubuntu1
* Get wpasupplicant 0.7.3 from Debian's SVN. Leaving 0.7.3-1 as unreleased
  for now.
* Build-Depend on debhelper 8, since the packaging from Debian uses compat 8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * WPA Supplicant / SSL/TLS interface functions for openssl
3
 
 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 
2
 * SSL/TLS interface functions for GnuTLS
 
3
 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License version 2 as
112
112
        int established;
113
113
        int verify_peer;
114
114
 
115
 
        u8 *push_buf, *pull_buf, *pull_buf_offset;
116
 
        size_t push_buf_len, pull_buf_len;
 
115
        struct wpabuf *push_buf;
 
116
        struct wpabuf *pull_buf;
 
117
        const u8 *pull_buf_offset;
117
118
 
118
119
        int params_set;
119
120
        gnutls_certificate_credentials_t xcred;
241
242
                             size_t len)
242
243
{
243
244
        struct tls_connection *conn = (struct tls_connection *) ptr;
244
 
        u8 *end;
 
245
        const u8 *end;
245
246
        if (conn->pull_buf == NULL) {
246
247
                errno = EWOULDBLOCK;
247
248
                return -1;
248
249
        }
249
250
 
250
 
        end = conn->pull_buf + conn->pull_buf_len;
 
251
        end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
251
252
        if ((size_t) (end - conn->pull_buf_offset) < len)
252
253
                len = end - conn->pull_buf_offset;
253
254
        os_memcpy(buf, conn->pull_buf_offset, len);
254
255
        conn->pull_buf_offset += len;
255
256
        if (conn->pull_buf_offset == end) {
256
257
                wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
257
 
                os_free(conn->pull_buf);
258
 
                conn->pull_buf = conn->pull_buf_offset = NULL;
259
 
                conn->pull_buf_len = 0;
 
258
                wpabuf_free(conn->pull_buf);
 
259
                conn->pull_buf = NULL;
 
260
                conn->pull_buf_offset = NULL;
260
261
        } else {
261
262
                wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
262
263
                           __func__,
270
271
                             size_t len)
271
272
{
272
273
        struct tls_connection *conn = (struct tls_connection *) ptr;
273
 
        u8 *nbuf;
274
274
 
275
 
        nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
276
 
        if (nbuf == NULL) {
 
275
        if (wpabuf_resize(&conn->push_buf, len) < 0) {
277
276
                errno = ENOMEM;
278
277
                return -1;
279
278
        }
280
 
        os_memcpy(nbuf + conn->push_buf_len, buf, len);
281
 
        conn->push_buf = nbuf;
282
 
        conn->push_buf_len += len;
 
279
        wpabuf_put_data(conn->push_buf, buf, len);
283
280
 
284
281
        return len;
285
282
}
383
380
        os_free(conn->pre_shared_secret);
384
381
        os_free(conn->subject_match);
385
382
        os_free(conn->altsubject_match);
386
 
        os_free(conn->push_buf);
387
 
        os_free(conn->pull_buf);
 
383
        wpabuf_free(conn->push_buf);
 
384
        wpabuf_free(conn->pull_buf);
388
385
        os_free(conn);
389
386
}
390
387
 
407
404
         * because the connection was already terminated in practice
408
405
         * and "close notify" shutdown alert would confuse AS. */
409
406
        gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
410
 
        os_free(conn->push_buf);
 
407
        wpabuf_free(conn->push_buf);
411
408
        conn->push_buf = NULL;
412
 
        conn->push_buf_len = 0;
413
409
        conn->established = 0;
414
410
        conn->final_phase_finished = 0;
415
411
#ifdef GNUTLS_IA
979
975
}
980
976
 
981
977
 
982
 
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
983
 
                              const u8 *in_data, size_t in_len,
984
 
                              size_t *out_len, u8 **appl_data,
985
 
                              size_t *appl_data_len)
986
 
{
987
 
        struct tls_global *global = ssl_ctx;
988
 
        u8 *out_data;
 
978
static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
 
979
{
 
980
        int res;
 
981
        struct wpabuf *ad;
 
982
        wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
 
983
        ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
 
984
        if (ad == NULL)
 
985
                return NULL;
 
986
 
 
987
        res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
 
988
                                 wpabuf_size(ad));
 
989
        wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
 
990
        if (res < 0) {
 
991
                wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
 
992
                           "(%s)", __func__, (int) res,
 
993
                           gnutls_strerror(res));
 
994
                wpabuf_free(ad);
 
995
                return NULL;
 
996
        }
 
997
 
 
998
        wpabuf_put(ad, res);
 
999
        wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
 
1000
                   res);
 
1001
        return ad;
 
1002
}
 
1003
 
 
1004
 
 
1005
struct wpabuf * tls_connection_handshake(void *tls_ctx,
 
1006
                                         struct tls_connection *conn,
 
1007
                                         const struct wpabuf *in_data,
 
1008
                                         struct wpabuf **appl_data)
 
1009
{
 
1010
        struct tls_global *global = tls_ctx;
 
1011
        struct wpabuf *out_data;
989
1012
        int ret;
990
1013
 
991
1014
        if (appl_data)
992
1015
                *appl_data = NULL;
993
1016
 
994
 
        if (in_data && in_len) {
 
1017
        if (in_data && wpabuf_len(in_data) > 0) {
995
1018
                if (conn->pull_buf) {
996
1019
                        wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
997
1020
                                   "pull_buf", __func__,
998
 
                                   (unsigned long) conn->pull_buf_len);
999
 
                        os_free(conn->pull_buf);
 
1021
                                   (unsigned long) wpabuf_len(conn->pull_buf));
 
1022
                        wpabuf_free(conn->pull_buf);
1000
1023
                }
1001
 
                conn->pull_buf = os_malloc(in_len);
 
1024
                conn->pull_buf = wpabuf_dup(in_data);
1002
1025
                if (conn->pull_buf == NULL)
1003
1026
                        return NULL;
1004
 
                os_memcpy(conn->pull_buf, in_data, in_len);
1005
 
                conn->pull_buf_offset = conn->pull_buf;
1006
 
                conn->pull_buf_len = in_len;
 
1027
                conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1007
1028
        }
1008
1029
 
1009
1030
        ret = gnutls_handshake(conn->session);
1014
1035
                            conn->push_buf == NULL) {
1015
1036
                                /* Need to return something to trigger
1016
1037
                                 * completion of EAP-TLS. */
1017
 
                                conn->push_buf = os_malloc(1);
 
1038
                                conn->push_buf = wpabuf_alloc(0);
1018
1039
                        }
1019
1040
                        break;
1020
1041
                case GNUTLS_E_FATAL_ALERT_RECEIVED:
1058
1079
                conn->established = 1;
1059
1080
                if (conn->push_buf == NULL) {
1060
1081
                        /* Need to return something to get final TLS ACK. */
1061
 
                        conn->push_buf = os_malloc(1);
 
1082
                        conn->push_buf = wpabuf_alloc(0);
1062
1083
                }
1063
1084
 
1064
1085
                gnutls_session_get_data(conn->session, NULL, &size);
1073
1094
                                                global->session_data,
1074
1095
                                                &global->session_data_size);
1075
1096
                }
 
1097
 
 
1098
                if (conn->pull_buf && appl_data)
 
1099
                        *appl_data = gnutls_get_appl_data(conn);
1076
1100
        }
1077
1101
 
1078
1102
out:
1079
1103
        out_data = conn->push_buf;
1080
 
        *out_len = conn->push_buf_len;
1081
1104
        conn->push_buf = NULL;
1082
 
        conn->push_buf_len = 0;
1083
1105
        return out_data;
1084
1106
}
1085
1107
 
1086
1108
 
1087
 
u8 * tls_connection_server_handshake(void *ssl_ctx,
1088
 
                                     struct tls_connection *conn,
1089
 
                                     const u8 *in_data, size_t in_len,
1090
 
                                     size_t *out_len)
 
1109
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
 
1110
                                                struct tls_connection *conn,
 
1111
                                                const struct wpabuf *in_data,
 
1112
                                                struct wpabuf **appl_data)
1091
1113
{
1092
 
        return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
1093
 
                                        out_len, NULL, NULL);
 
1114
        return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1094
1115
}
1095
1116
 
1096
1117
 
1097
 
int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
1098
 
                           const u8 *in_data, size_t in_len,
1099
 
                           u8 *out_data, size_t out_len)
 
1118
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
 
1119
                                       struct tls_connection *conn,
 
1120
                                       const struct wpabuf *in_data)
1100
1121
{
1101
1122
        ssize_t res;
 
1123
        struct wpabuf *buf;
1102
1124
 
1103
1125
#ifdef GNUTLS_IA
1104
1126
        if (conn->tls_ia)
1105
 
                res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
 
1127
                res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
 
1128
                                     wpabuf_len(in_data));
1106
1129
        else
1107
1130
#endif /* GNUTLS_IA */
1108
 
        res = gnutls_record_send(conn->session, in_data, in_len);
 
1131
        res = gnutls_record_send(conn->session, wpabuf_head(in_data),
 
1132
                                 wpabuf_len(in_data));
1109
1133
        if (res < 0) {
1110
1134
                wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1111
1135
                           __func__, gnutls_strerror(res));
1112
 
                return -1;
1113
 
        }
1114
 
        if (conn->push_buf == NULL)
1115
 
                return -1;
1116
 
        if (conn->push_buf_len < out_len)
1117
 
                out_len = conn->push_buf_len;
1118
 
        else if (conn->push_buf_len > out_len) {
1119
 
                wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for "
1120
 
                           "encrypted message (in_len=%lu push_buf_len=%lu "
1121
 
                           "out_len=%lu",
1122
 
                           (unsigned long) in_len,
1123
 
                           (unsigned long) conn->push_buf_len,
1124
 
                           (unsigned long) out_len);
1125
 
        }
1126
 
        os_memcpy(out_data, conn->push_buf, out_len);
1127
 
        os_free(conn->push_buf);
 
1136
                return NULL;
 
1137
        }
 
1138
 
 
1139
        buf = conn->push_buf;
1128
1140
        conn->push_buf = NULL;
1129
 
        conn->push_buf_len = 0;
1130
 
        return out_len;
 
1141
        return buf;
1131
1142
}
1132
1143
 
1133
1144
 
1134
 
int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
1135
 
                           const u8 *in_data, size_t in_len,
1136
 
                           u8 *out_data, size_t out_len)
 
1145
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 
1146
                                       struct tls_connection *conn,
 
1147
                                       const struct wpabuf *in_data)
1137
1148
{
1138
1149
        ssize_t res;
 
1150
        struct wpabuf *out;
1139
1151
 
1140
1152
        if (conn->pull_buf) {
1141
1153
                wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1142
1154
                           "pull_buf", __func__,
1143
 
                           (unsigned long) conn->pull_buf_len);
1144
 
                os_free(conn->pull_buf);
 
1155
                           (unsigned long) wpabuf_len(conn->pull_buf));
 
1156
                wpabuf_free(conn->pull_buf);
1145
1157
        }
1146
 
        conn->pull_buf = os_malloc(in_len);
 
1158
        conn->pull_buf = wpabuf_dup(in_data);
1147
1159
        if (conn->pull_buf == NULL)
1148
 
                return -1;
1149
 
        os_memcpy(conn->pull_buf, in_data, in_len);
1150
 
        conn->pull_buf_offset = conn->pull_buf;
1151
 
        conn->pull_buf_len = in_len;
 
1160
                return NULL;
 
1161
        conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
 
1162
 
 
1163
        /*
 
1164
         * Even though we try to disable TLS compression, it is possible that
 
1165
         * this cannot be done with all TLS libraries. Add extra buffer space
 
1166
         * to handle the possibility of the decrypted data being longer than
 
1167
         * input data.
 
1168
         */
 
1169
        out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
 
1170
        if (out == NULL)
 
1171
                return NULL;
1152
1172
 
1153
1173
#ifdef GNUTLS_IA
1154
1174
        if (conn->tls_ia) {
1155
 
                res = gnutls_ia_recv(conn->session, (char *) out_data,
1156
 
                                     out_len);
1157
 
                if (out_len >= 12 &&
1158
 
                    (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
1159
 
                     res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
 
1175
                res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
 
1176
                                     wpabuf_size(out));
 
1177
                if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
 
1178
                    res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
1160
1179
                        int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
1161
1180
                        wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
1162
1181
                                   __func__, final ? "Final" : "Intermediate");
1175
1194
                                wpa_printf(MSG_DEBUG, "%s: Failed to permute "
1176
1195
                                           "inner secret: %s",
1177
1196
                                           __func__, gnutls_strerror(res));
1178
 
                                return -1;
 
1197
                                wpabuf_free(out);
 
1198
                                return NULL;
1179
1199
                        }
1180
1200
 
1181
1201
                        res = gnutls_ia_verify_endphase(conn->session,
1182
 
                                                        (char *) out_data);
 
1202
                                                        wpabuf_head(out));
1183
1203
                        if (res == 0) {
1184
1204
                                wpa_printf(MSG_DEBUG, "%s: Correct endphase "
1185
1205
                                           "checksum", __func__);
1187
1207
                                wpa_printf(MSG_INFO, "%s: Endphase "
1188
1208
                                           "verification failed: %s",
1189
1209
                                           __func__, gnutls_strerror(res));
1190
 
                                return -1;
 
1210
                                wpabuf_free(out);
 
1211
                                return NULL;
1191
1212
                        }
1192
1213
 
1193
1214
                        if (final)
1194
1215
                                conn->final_phase_finished = 1;
1195
1216
 
1196
 
                        return 0;
 
1217
                        return out;
1197
1218
                }
1198
1219
 
1199
1220
                if (res < 0) {
1200
1221
                        wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
1201
1222
                                   "(%s)", __func__, (int) res,
1202
1223
                                   gnutls_strerror(res));
 
1224
                        wpabuf_free(out);
 
1225
                        return NULL;
1203
1226
                }
1204
 
                return res;
 
1227
                wpabuf_put(out, res);
 
1228
                return out;
1205
1229
        }
1206
1230
#endif /* GNUTLS_IA */
1207
1231
 
1208
 
        res = gnutls_record_recv(conn->session, out_data, out_len);
 
1232
        res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
 
1233
                                 wpabuf_size(out));
1209
1234
        if (res < 0) {
1210
1235
                wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1211
1236
                           "(%s)", __func__, (int) res, gnutls_strerror(res));
 
1237
                wpabuf_free(out);
 
1238
                return NULL;
1212
1239
        }
 
1240
        wpabuf_put(out, res);
1213
1241
 
1214
 
        return res;
 
1242
        return out;
1215
1243
}
1216
1244
 
1217
1245
 
1243
1271
int tls_connection_enable_workaround(void *ssl_ctx,
1244
1272
                                     struct tls_connection *conn)
1245
1273
{
1246
 
        /* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
 
1274
        gnutls_record_disable_padding(conn->session);
1247
1275
        return 0;
1248
1276
}
1249
1277
 
1338
1366
}
1339
1367
 
1340
1368
 
1341
 
int tls_connection_ia_send_phase_finished(void *tls_ctx,
1342
 
                                          struct tls_connection *conn,
1343
 
                                          int final,
1344
 
                                          u8 *out_data, size_t out_len)
 
1369
struct wpabuf * tls_connection_ia_send_phase_finished(
 
1370
        void *tls_ctx, struct tls_connection *conn, int final)
1345
1371
{
1346
1372
#ifdef GNUTLS_IA
1347
1373
        int ret;
 
1374
        struct wpabuf *buf;
1348
1375
 
1349
1376
        if (conn == NULL || conn->session == NULL || !conn->tls_ia)
1350
 
                return -1;
 
1377
                return NULL;
1351
1378
 
1352
1379
        ret = gnutls_ia_permute_inner_secret(conn->session,
1353
1380
                                             conn->session_keys_len,
1361
1388
        if (ret) {
1362
1389
                wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
1363
1390
                           __func__, gnutls_strerror(ret));
1364
 
                return -1;
 
1391
                return NULL;
1365
1392
        }
1366
1393
 
1367
1394
        ret = gnutls_ia_endphase_send(conn->session, final);
1368
1395
        if (ret) {
1369
1396
                wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
1370
1397
                           __func__, gnutls_strerror(ret));
1371
 
                return -1;
 
1398
                return NULL;
1372
1399
        }
1373
1400
 
1374
 
        if (conn->push_buf == NULL)
1375
 
                return -1;
1376
 
        if (conn->push_buf_len < out_len)
1377
 
                out_len = conn->push_buf_len;
1378
 
        os_memcpy(out_data, conn->push_buf, out_len);
1379
 
        os_free(conn->push_buf);
 
1401
        buf = conn->push_buf;
1380
1402
        conn->push_buf = NULL;
1381
 
        conn->push_buf_len = 0;
1382
 
        return out_len;
 
1403
        return buf;
1383
1404
#else /* GNUTLS_IA */
1384
 
        return -1;
 
1405
        return NULL;
1385
1406
#endif /* GNUTLS_IA */
1386
1407
}
1387
1408
 
1426
1447
        return -1;
1427
1448
#endif /* GNUTLS_IA */
1428
1449
}
 
1450
 
 
1451
 
 
1452
int tls_connection_set_session_ticket_cb(void *tls_ctx,
 
1453
                                         struct tls_connection *conn,
 
1454
                                         tls_session_ticket_cb cb, void *ctx)
 
1455
{
 
1456
        return -1;
 
1457
}