~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/tls/tlsv1_cred.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * TLSv1 credentials
 
3
 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 2 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * Alternatively, this software may be distributed under the terms of BSD
 
10
 * license.
 
11
 *
 
12
 * See README and COPYING for more details.
 
13
 */
 
14
 
 
15
#include "includes.h"
 
16
 
 
17
#include "common.h"
 
18
#include "base64.h"
 
19
#include "crypto.h"
 
20
#include "x509v3.h"
 
21
#include "tlsv1_cred.h"
 
22
 
 
23
 
 
24
struct tlsv1_credentials * tlsv1_cred_alloc(void)
 
25
{
 
26
        struct tlsv1_credentials *cred;
 
27
        cred = os_zalloc(sizeof(*cred));
 
28
        return cred;
 
29
}
 
30
 
 
31
 
 
32
void tlsv1_cred_free(struct tlsv1_credentials *cred)
 
33
{
 
34
        if (cred == NULL)
 
35
                return;
 
36
 
 
37
        x509_certificate_chain_free(cred->trusted_certs);
 
38
        x509_certificate_chain_free(cred->cert);
 
39
        crypto_private_key_free(cred->key);
 
40
        os_free(cred->dh_p);
 
41
        os_free(cred->dh_g);
 
42
        os_free(cred);
 
43
}
 
44
 
 
45
 
 
46
static int tlsv1_add_cert_der(struct x509_certificate **chain,
 
47
                              const u8 *buf, size_t len)
 
48
{
 
49
        struct x509_certificate *cert;
 
50
        char name[128];
 
51
 
 
52
        cert = x509_certificate_parse(buf, len);
 
53
        if (cert == NULL) {
 
54
                wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
 
55
                           __func__);
 
56
                return -1;
 
57
        }
 
58
 
 
59
        cert->next = *chain;
 
60
        *chain = cert;
 
61
 
 
62
        x509_name_string(&cert->subject, name, sizeof(name));
 
63
        wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
 
64
 
 
65
        return 0;
 
66
}
 
67
 
 
68
 
 
69
static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
 
70
static const char *pem_cert_end = "-----END CERTIFICATE-----";
 
71
 
 
72
 
 
73
static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
 
74
{
 
75
        size_t i, plen;
 
76
 
 
77
        plen = os_strlen(tag);
 
78
        if (len < plen)
 
79
                return NULL;
 
80
 
 
81
        for (i = 0; i < len - plen; i++) {
 
82
                if (os_memcmp(buf + i, tag, plen) == 0)
 
83
                        return buf + i;
 
84
        }
 
85
 
 
86
        return NULL;
 
87
}
 
88
 
 
89
 
 
90
static int tlsv1_add_cert(struct x509_certificate **chain,
 
91
                          const u8 *buf, size_t len)
 
92
{
 
93
        const u8 *pos, *end;
 
94
        unsigned char *der;
 
95
        size_t der_len;
 
96
 
 
97
        pos = search_tag(pem_cert_begin, buf, len);
 
98
        if (!pos) {
 
99
                wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
 
100
                           "assume DER format");
 
101
                return tlsv1_add_cert_der(chain, buf, len);
 
102
        }
 
103
 
 
104
        wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
 
105
                   "DER format");
 
106
 
 
107
        while (pos) {
 
108
                pos += os_strlen(pem_cert_begin);
 
109
                end = search_tag(pem_cert_end, pos, buf + len - pos);
 
110
                if (end == NULL) {
 
111
                        wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
 
112
                                   "certificate end tag (%s)", pem_cert_end);
 
113
                        return -1;
 
114
                }
 
115
 
 
116
                der = base64_decode(pos, end - pos, &der_len);
 
117
                if (der == NULL) {
 
118
                        wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
 
119
                                   "certificate");
 
120
                        return -1;
 
121
                }
 
122
 
 
123
                if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
 
124
                        wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
 
125
                                   "certificate after DER conversion");
 
126
                        os_free(der);
 
127
                        return -1;
 
128
                }
 
129
 
 
130
                os_free(der);
 
131
 
 
132
                end += os_strlen(pem_cert_end);
 
133
                pos = search_tag(pem_cert_begin, end, buf + len - end);
 
134
        }
 
135
 
 
136
        return 0;
 
137
}
 
138
 
 
139
 
 
140
static int tlsv1_set_cert_chain(struct x509_certificate **chain,
 
141
                                const char *cert, const u8 *cert_blob,
 
142
                                size_t cert_blob_len)
 
143
{
 
144
        if (cert_blob)
 
145
                return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
 
146
 
 
147
        if (cert) {
 
148
                u8 *buf;
 
149
                size_t len;
 
150
                int ret;
 
151
 
 
152
                buf = (u8 *) os_readfile(cert, &len);
 
153
                if (buf == NULL) {
 
154
                        wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 
155
                                   cert);
 
156
                        return -1;
 
157
                }
 
158
 
 
159
                ret = tlsv1_add_cert(chain, buf, len);
 
160
                os_free(buf);
 
161
                return ret;
 
162
        }
 
163
 
 
164
        return 0;
 
165
}
 
166
 
 
167
 
 
168
/**
 
169
 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
 
170
 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
 
171
 * @cert: File or reference name for X.509 certificate in PEM or DER format
 
172
 * @cert_blob: cert as inlined data or %NULL if not used
 
173
 * @cert_blob_len: ca_cert_blob length
 
174
 * @path: Path to CA certificates (not yet supported)
 
175
 * Returns: 0 on success, -1 on failure
 
176
 */
 
177
int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
 
178
                      const u8 *cert_blob, size_t cert_blob_len,
 
179
                      const char *path)
 
180
{
 
181
        if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
 
182
                                 cert_blob, cert_blob_len) < 0)
 
183
                return -1;
 
184
 
 
185
        if (path) {
 
186
                /* TODO: add support for reading number of certificate files */
 
187
                wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
 
188
                           "not yet supported");
 
189
                return -1;
 
190
        }
 
191
 
 
192
        return 0;
 
193
}
 
194
 
 
195
 
 
196
/**
 
197
 * tlsv1_set_cert - Set certificate
 
198
 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
 
199
 * @cert: File or reference name for X.509 certificate in PEM or DER format
 
200
 * @cert_blob: cert as inlined data or %NULL if not used
 
201
 * @cert_blob_len: cert_blob length
 
202
 * Returns: 0 on success, -1 on failure
 
203
 */
 
204
int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
 
205
                   const u8 *cert_blob, size_t cert_blob_len)
 
206
{
 
207
        return tlsv1_set_cert_chain(&cred->cert, cert,
 
208
                                    cert_blob, cert_blob_len);
 
209
}
 
210
 
 
211
 
 
212
static int tlsv1_set_key(struct tlsv1_credentials *cred,
 
213
                         const u8 *key, size_t len)
 
214
{
 
215
        cred->key = crypto_private_key_import(key, len);
 
216
        if (cred->key == NULL) {
 
217
                wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
 
218
                return -1;
 
219
        }
 
220
        return 0;
 
221
}
 
222
 
 
223
 
 
224
/**
 
225
 * tlsv1_set_private_key - Set private key
 
226
 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
 
227
 * @private_key: File or reference name for the key in PEM or DER format
 
228
 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
 
229
 * passphrase is used.
 
230
 * @private_key_blob: private_key as inlined data or %NULL if not used
 
231
 * @private_key_blob_len: private_key_blob length
 
232
 * Returns: 0 on success, -1 on failure
 
233
 */
 
234
int tlsv1_set_private_key(struct tlsv1_credentials *cred,
 
235
                          const char *private_key,
 
236
                          const char *private_key_passwd,
 
237
                          const u8 *private_key_blob,
 
238
                          size_t private_key_blob_len)
 
239
{
 
240
        crypto_private_key_free(cred->key);
 
241
        cred->key = NULL;
 
242
 
 
243
        if (private_key_blob)
 
244
                return tlsv1_set_key(cred, private_key_blob,
 
245
                                     private_key_blob_len);
 
246
 
 
247
        if (private_key) {
 
248
                u8 *buf;
 
249
                size_t len;
 
250
                int ret;
 
251
 
 
252
                buf = (u8 *) os_readfile(private_key, &len);
 
253
                if (buf == NULL) {
 
254
                        wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 
255
                                   private_key);
 
256
                        return -1;
 
257
                }
 
258
 
 
259
                ret = tlsv1_set_key(cred, buf, len);
 
260
                os_free(buf);
 
261
                return ret;
 
262
        }
 
263
 
 
264
        return 0;
 
265
}
 
266
 
 
267
 
 
268
static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
 
269
                                  const u8 *dh, size_t len)
 
270
{
 
271
        struct asn1_hdr hdr;
 
272
        const u8 *pos, *end;
 
273
 
 
274
        pos = dh;
 
275
        end = dh + len;
 
276
 
 
277
        /*
 
278
         * DHParameter ::= SEQUENCE {
 
279
         *   prime INTEGER, -- p
 
280
         *   base INTEGER, -- g
 
281
         *   privateValueLength INTEGER OPTIONAL }
 
282
         */
 
283
 
 
284
        /* DHParamer ::= SEQUENCE */
 
285
        if (asn1_get_next(pos, len, &hdr) < 0 ||
 
286
            hdr.class != ASN1_CLASS_UNIVERSAL ||
 
287
            hdr.tag != ASN1_TAG_SEQUENCE) {
 
288
                wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
 
289
                           "valid SEQUENCE - found class %d tag 0x%x",
 
290
                           hdr.class, hdr.tag);
 
291
                return -1;
 
292
        }
 
293
        pos = hdr.payload;
 
294
 
 
295
        /* prime INTEGER */
 
296
        if (asn1_get_next(pos, end - pos, &hdr) < 0)
 
297
                return -1;
 
298
 
 
299
        if (hdr.class != ASN1_CLASS_UNIVERSAL ||
 
300
            hdr.tag != ASN1_TAG_INTEGER) {
 
301
                wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
 
302
                           "class=%d tag=0x%x", hdr.class, hdr.tag);
 
303
                return -1;
 
304
        }
 
305
 
 
306
        wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
 
307
        if (hdr.length == 0)
 
308
                return -1;
 
309
        os_free(cred->dh_p);
 
310
        cred->dh_p = os_malloc(hdr.length);
 
311
        if (cred->dh_p == NULL)
 
312
                return -1;
 
313
        os_memcpy(cred->dh_p, hdr.payload, hdr.length);
 
314
        cred->dh_p_len = hdr.length;
 
315
        pos = hdr.payload + hdr.length;
 
316
 
 
317
        /* base INTEGER */
 
318
        if (asn1_get_next(pos, end - pos, &hdr) < 0)
 
319
                return -1;
 
320
 
 
321
        if (hdr.class != ASN1_CLASS_UNIVERSAL ||
 
322
            hdr.tag != ASN1_TAG_INTEGER) {
 
323
                wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
 
324
                           "class=%d tag=0x%x", hdr.class, hdr.tag);
 
325
                return -1;
 
326
        }
 
327
 
 
328
        wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
 
329
        if (hdr.length == 0)
 
330
                return -1;
 
331
        os_free(cred->dh_g);
 
332
        cred->dh_g = os_malloc(hdr.length);
 
333
        if (cred->dh_g == NULL)
 
334
                return -1;
 
335
        os_memcpy(cred->dh_g, hdr.payload, hdr.length);
 
336
        cred->dh_g_len = hdr.length;
 
337
 
 
338
        return 0;
 
339
}
 
340
 
 
341
 
 
342
static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
 
343
static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
 
344
 
 
345
 
 
346
static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
 
347
                                   const u8 *buf, size_t len)
 
348
{
 
349
        const u8 *pos, *end;
 
350
        unsigned char *der;
 
351
        size_t der_len;
 
352
 
 
353
        pos = search_tag(pem_dhparams_begin, buf, len);
 
354
        if (!pos) {
 
355
                wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
 
356
                           "assume DER format");
 
357
                return tlsv1_set_dhparams_der(cred, buf, len);
 
358
        }
 
359
 
 
360
        wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
 
361
                   "format");
 
362
 
 
363
        pos += os_strlen(pem_dhparams_begin);
 
364
        end = search_tag(pem_dhparams_end, pos, buf + len - pos);
 
365
        if (end == NULL) {
 
366
                wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
 
367
                           "tag (%s)", pem_dhparams_end);
 
368
                return -1;
 
369
        }
 
370
 
 
371
        der = base64_decode(pos, end - pos, &der_len);
 
372
        if (der == NULL) {
 
373
                wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
 
374
                return -1;
 
375
        }
 
376
 
 
377
        if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
 
378
                wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
 
379
                           "DER conversion");
 
380
                os_free(der);
 
381
                return -1;
 
382
        }
 
383
 
 
384
        os_free(der);
 
385
 
 
386
        return 0;
 
387
}
 
388
 
 
389
 
 
390
/**
 
391
 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
 
392
 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
 
393
 * @dh_file: File or reference name for the DH params in PEM or DER format
 
394
 * @dh_blob: DH params as inlined data or %NULL if not used
 
395
 * @dh_blob_len: dh_blob length
 
396
 * Returns: 0 on success, -1 on failure
 
397
 */
 
398
int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
 
399
                       const u8 *dh_blob, size_t dh_blob_len)
 
400
{
 
401
        if (dh_blob)
 
402
                return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
 
403
 
 
404
        if (dh_file) {
 
405
                u8 *buf;
 
406
                size_t len;
 
407
                int ret;
 
408
 
 
409
                buf = (u8 *) os_readfile(dh_file, &len);
 
410
                if (buf == NULL) {
 
411
                        wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
 
412
                                   dh_file);
 
413
                        return -1;
 
414
                }
 
415
 
 
416
                ret = tlsv1_set_dhparams_blob(cred, buf, len);
 
417
                os_free(buf);
 
418
                return ret;
 
419
        }
 
420
 
 
421
        return 0;
 
422
}