]> git.sesse.net Git - vlc/blob - src/misc/update.c
Interaction: remove (buggy and useless) dialog IDs
[vlc] / src / misc / update.c
1 /*****************************************************************************
2  * update.c: VLC update checking and downloading
3  *****************************************************************************
4  * Copyright © 2005-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
8  *          Rémi Duraffort <ivoire at via.ecp.fr>
9             Rafaël Carré <funman@videolanorg>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either release 2 of the License, or
14  * (at your option) any later release.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /**
27  *   \file
28  *   This file contains functions related to VLC update management
29  */
30
31 /*****************************************************************************
32  * Preamble
33  *****************************************************************************/
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38 #ifdef HAVE_SYS_STAT_H
39 #   include <sys/stat.h>
40 #endif
41
42 #include <vlc_common.h>
43 #include <vlc_update.h>
44
45 #ifdef UPDATE_CHECK
46
47 #include <assert.h>
48
49 #include <vlc_pgpkey.h>
50 #include <vlc_stream.h>
51 #include <vlc_strings.h>
52 #include <vlc_charset.h>
53 #include <vlc_interface.h>
54
55 #include <gcrypt.h>
56 #include <vlc_gcrypt.h>
57
58 #include "update.h"
59 #include "../libvlc.h"
60
61 /*****************************************************************************
62  * Misc defines
63  *****************************************************************************/
64
65 /*
66  * Here is the format of these "status files" :
67  * First line is the last version: "X.Y.Ze" where:
68  *      * X is the major number
69  *      * Y is the minor number
70  *      * Z is the revision number
71  *      * e is an OPTIONAL extra letter
72  *      * AKA "0.8.6d" or "0.9.0"
73  * Second line is an url of the binary for this last version
74  * Remaining text is a required description of the update
75  */
76
77 #if defined( UNDER_CE )
78 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
79 #elif defined( WIN32 )
80 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
81 #elif defined( __APPLE__ )
82 #   if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
83 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-ppc"
84 #   else
85 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
86 #   endif
87 #elif defined( SYS_BEOS )
88 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
89 #else
90 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
91 #endif
92
93
94 /*****************************************************************************
95  * Local Prototypes
96  *****************************************************************************/
97 static void EmptyRelease( update_t *p_update );
98 static bool GetUpdateFile( update_t *p_update );
99 static char * size_str( long int l_size );
100
101
102 /*****************************************************************************
103  * OpenPGP functions
104  *****************************************************************************/
105
106 #define packet_type( c ) ( ( c & 0x3c ) >> 2 )      /* 0x3C = 00111100 */
107 #define packet_header_len( c ) ( ( c & 0x03 ) + 1 ) /* number of bytes in a packet header */
108
109 static inline int scalar_number( uint8_t *p, int header_len )
110 {
111     assert( header_len == 1 || header_len == 2 || header_len == 4 );
112
113     if( header_len == 1 )
114         return( p[0] );
115     else if( header_len == 2 )
116         return( (p[0] << 8) + p[1] );
117     else if( header_len == 4 )
118         return( (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3] );
119
120     abort(); /* to shut up GCC warning */
121 }
122
123 /* number of data bytes in a MPI */
124 #define mpi_len( mpi ) ( ( scalar_number( mpi, 2 ) + 7 ) / 8 )
125
126 /*
127  * fill a public_key_packet_t structure from public key packet data
128  * verify that it is a version 4 public key packet, using DSA
129  */
130 static int parse_public_key_packet( public_key_packet_t *p_key, uint8_t *p_buf,
131                                     size_t i_packet_len )
132 {
133
134     if( i_packet_len > 418 || i_packet_len < 6 )
135         return VLC_EGENERIC;
136
137     size_t i_read = 0;
138
139     p_key->version   = *p_buf++; i_read++;
140     if( p_key->version != 4 )
141         return VLC_EGENERIC;
142
143     /* XXX: warn when timestamp is > date ? */
144     memcpy( p_key->timestamp, p_buf, 4 ); p_buf += 4; i_read += 4;
145
146     p_key->algo      = *p_buf++; i_read++;
147     if( p_key->algo != PUBLIC_KEY_ALGO_DSA )
148         return VLC_EGENERIC;
149
150     /* read p */
151     if( i_read + 2 > i_packet_len )
152         return VLC_EGENERIC;
153
154     int i_p_len = mpi_len( p_buf );
155
156     if( i_p_len > 128 || i_read + 2 + i_p_len > i_packet_len )
157         return VLC_EGENERIC;
158
159     memcpy( p_key->p, p_buf, 2+i_p_len );
160     p_buf += 2+i_p_len; i_read += 2+i_p_len;
161
162     /* read q */
163     if( i_read + 2 > i_packet_len )
164         return VLC_EGENERIC;
165
166     int i_q_len = mpi_len( p_buf );
167
168     if( i_q_len > 20 || i_read+2+i_q_len > i_packet_len )
169         return VLC_EGENERIC;
170
171     memcpy( p_key->q, p_buf, 2+i_q_len );
172     p_buf += 2+i_q_len; i_read += 2+i_q_len;
173
174     /* read g */
175     if( i_read + 2 > i_packet_len )
176         return VLC_EGENERIC;
177
178     int i_g_len = mpi_len( p_buf );
179
180     if( i_g_len > 128 || i_read+2+i_g_len > i_packet_len )
181         return VLC_EGENERIC;
182
183     memcpy( p_key->g, p_buf, 2+i_g_len );
184     p_buf += 2+i_g_len; i_read += 2+i_g_len;
185
186     /* read y */
187     if( i_read + 2 > i_packet_len )
188         return VLC_EGENERIC;
189
190     int i_y_len = mpi_len( p_buf );
191
192
193     if( i_y_len > 128 || i_read+2+i_y_len > i_packet_len )
194         return VLC_EGENERIC;
195
196     memcpy( p_key->y, p_buf, 2+i_y_len );
197     i_read += 2+i_y_len;
198
199     if( i_read != i_packet_len ) /* some extra data eh ? */
200         return VLC_EGENERIC;
201
202     return VLC_SUCCESS;
203 }
204
205 static size_t parse_signature_v3_packet( signature_packet_t *p_sig,
206                                       uint8_t *p_buf, size_t i_sig_len )
207 {
208     size_t i_read = 1; /* we already read the version byte */
209
210     if( i_sig_len < 19 ) /* signature is at least 19 bytes + the 2 MPIs */
211         return 0;
212
213     p_sig->specific.v3.hashed_data_len = *p_buf++; i_read++;
214     if( p_sig->specific.v3.hashed_data_len != 5 )
215         return 0;
216
217     p_sig->type = *p_buf++; i_read++;
218
219     memcpy( p_sig->specific.v3.timestamp, p_buf, 4 );
220     p_buf += 4; i_read += 4;
221
222     memcpy( p_sig->issuer_longid, p_buf, 8 );
223     p_buf += 8; i_read += 8;
224
225     p_sig->public_key_algo = *p_buf++; i_read++;
226
227     p_sig->digest_algo = *p_buf++; i_read++;
228
229     p_sig->hash_verification[0] = *p_buf++; i_read++;
230     p_sig->hash_verification[1] = *p_buf++; i_read++;
231
232     assert( i_read == 19 );
233
234     return i_read;
235 }
236
237 /*
238  * fill a signature_packet_v4_t from signature packet data
239  * verify that it was used with a DSA public key, using SHA-1 digest
240  */
241 static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
242                                       uint8_t *p_buf, size_t i_sig_len )
243 {
244     size_t i_read = 1; /* we already read the version byte */
245
246     if( i_sig_len < 10 ) /* signature is at least 10 bytes + the 2 MPIs */
247         return 0;
248
249     p_sig->type = *p_buf++; i_read++;
250
251     p_sig->public_key_algo = *p_buf++; i_read++;
252
253     p_sig->digest_algo = *p_buf++; i_read++;
254
255     memcpy( p_sig->specific.v4.hashed_data_len, p_buf, 2 );
256     p_buf += 2; i_read += 2;
257
258     size_t i_hashed_data_len =
259         scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
260     i_read += i_hashed_data_len;
261     if( i_read + 4 > i_sig_len )
262         return 0;
263
264     p_sig->specific.v4.hashed_data = (uint8_t*) malloc( i_hashed_data_len );
265     if( !p_sig->specific.v4.hashed_data )
266         return 0;
267     memcpy( p_sig->specific.v4.hashed_data, p_buf, i_hashed_data_len );
268     p_buf += i_hashed_data_len;
269
270     memcpy( p_sig->specific.v4.unhashed_data_len, p_buf, 2 );
271     p_buf += 2; i_read += 2;
272
273     size_t i_unhashed_data_len =
274         scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
275     i_read += i_unhashed_data_len;
276     if( i_read + 2 > i_sig_len )
277         return 0;
278
279     p_sig->specific.v4.unhashed_data = (uint8_t*) malloc( i_unhashed_data_len );
280     if( !p_sig->specific.v4.unhashed_data )
281         return 0;
282
283     memcpy( p_sig->specific.v4.unhashed_data, p_buf, i_unhashed_data_len );
284     p_buf += i_unhashed_data_len;
285
286     memcpy( p_sig->hash_verification, p_buf, 2 );
287     p_buf += 2; i_read += 2;
288
289     uint8_t *p, *max_pos;
290     p = p_sig->specific.v4.unhashed_data;
291     max_pos = p + scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
292
293     for( ;; )
294     {
295         if( p > max_pos )
296             return 0;
297
298         size_t i_subpacket_len;
299         if( *p < 192 )
300         {
301             if( p + 1 > max_pos )
302                 return 0;
303             i_subpacket_len = *p++;
304         }
305         else if( *p < 255 )
306         {
307             if( p + 2 > max_pos )
308                 return 0;
309             i_subpacket_len = (*p++ - 192) << 8;
310             i_subpacket_len += *p++ + 192;
311         }
312         else
313         {
314             if( p + 4 > max_pos )
315                 return 0;
316             i_subpacket_len = *++p << 24;
317             i_subpacket_len += *++p << 16;
318             i_subpacket_len += *++p << 8;
319             i_subpacket_len += *++p;
320         }
321
322         if( *p == ISSUER_SUBPACKET )
323         {
324             if( p + 9 > max_pos )
325                 return 0;
326
327             memcpy( &p_sig->issuer_longid, p+1, 8 );
328
329             return i_read;
330         }
331
332         p += i_subpacket_len;
333     }
334 }
335
336 static int parse_signature_packet( signature_packet_t *p_sig,
337                                    uint8_t *p_buf, size_t i_sig_len )
338 {
339     if( !i_sig_len ) /* 1st sanity check, we need at least the version */
340         return VLC_EGENERIC;
341
342     p_sig->version = *p_buf++;
343
344     size_t i_read;
345     switch( p_sig->version )
346     {
347         case 3:
348             i_read = parse_signature_v3_packet( p_sig, p_buf, i_sig_len );
349             break;
350         case 4:
351             p_sig->specific.v4.hashed_data = NULL;
352             p_sig->specific.v4.unhashed_data = NULL;
353             i_read = parse_signature_v4_packet( p_sig, p_buf, i_sig_len );
354             break;
355         default:
356             return VLC_EGENERIC;
357     }
358
359     if( i_read == 0 ) /* signature packet parsing has failed */
360         goto error;
361
362     if( p_sig->public_key_algo != PUBLIC_KEY_ALGO_DSA )
363         goto error;
364
365     if( p_sig->digest_algo != DIGEST_ALGO_SHA1 )
366         goto error;
367
368     switch( p_sig->type )
369     {
370         case BINARY_SIGNATURE:
371         case TEXT_SIGNATURE:
372         case GENERIC_KEY_SIGNATURE:
373         case PERSONA_KEY_SIGNATURE:
374         case CASUAL_KEY_SIGNATURE:
375         case POSITIVE_KEY_SIGNATURE:
376             break;
377         default:
378             goto error;
379     }
380
381     p_buf--; /* rewind to the version byte */
382     p_buf += i_read;
383
384     if( i_read + 2 > i_sig_len )
385         goto error;
386
387     size_t i_r_len = mpi_len( p_buf ); i_read += 2;
388     if( i_read + i_r_len > i_sig_len || i_r_len > 20 )
389         goto error;
390
391     memcpy( p_sig->r, p_buf, 2 + i_r_len );
392     p_buf += 2 + i_r_len;
393     i_read += i_r_len;
394
395     if( i_read + 2 > i_sig_len )
396         goto error;
397
398     size_t i_s_len = mpi_len( p_buf ); i_read += 2;
399     if( i_read + i_s_len > i_sig_len || i_s_len > 20 )
400         goto error;
401
402     memcpy( p_sig->s, p_buf, 2 + i_s_len );
403     p_buf += 2 + i_s_len;
404     i_read += i_s_len;
405
406     assert( i_read == i_sig_len );
407     if( i_read < i_sig_len ) /* some extra data, hm ? */
408         goto error;
409
410     return VLC_SUCCESS;
411
412 error:
413
414     if( p_sig->version == 4 )
415     {
416         free( p_sig->specific.v4.hashed_data );
417         free( p_sig->specific.v4.unhashed_data );
418     }
419
420     return VLC_EGENERIC;
421 }
422
423 /*
424  * crc_octets() was lamely copied from rfc 2440
425  * Copyright (C) The Internet Society (1998).  All Rights Reserved.
426  */
427 #define CRC24_INIT 0xB704CEL
428 #define CRC24_POLY 0x1864CFBL
429
430 static long crc_octets( uint8_t *octets, size_t len )
431 {
432     long crc = CRC24_INIT;
433     int i;
434     while (len--)
435     {
436         crc ^= (*octets++) << 16;
437         for (i = 0; i < 8; i++)
438         {
439             crc <<= 1;
440             if (crc & 0x1000000)
441                 crc ^= CRC24_POLY;
442         }
443     }
444     return crc & 0xFFFFFFL;
445 }
446
447 /*
448  * Transform an armored document in binary format
449  * Used on public keys and signatures
450  */
451 static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
452                         uint8_t *p_obuf, size_t i_obuf_len )
453 {
454     char *p_ipos = p_ibuf;
455     uint8_t *p_opos = p_obuf;
456     int i_end = 0;
457     int i_header_skipped = 0;
458
459     while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' )
460     {
461         if( *p_ipos == '\r' || *p_ipos == '\n' )
462         {
463             p_ipos++;
464             continue;
465         }
466
467         size_t i_line_len = strcspn( p_ipos, "\r\n" );
468         if( i_line_len == 0 )
469             continue;
470
471         if( !i_header_skipped )
472         {
473             if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) )
474                 i_header_skipped = 1;
475
476             p_ipos += i_line_len + 1;
477             continue;
478         }
479
480         if( !strncmp( p_ipos, "Version:", 8 ) )
481         {
482             p_ipos += i_line_len + 1;
483             continue;
484         }
485
486         if( p_ipos[i_line_len - 1] == '=' )
487         {
488             i_end = 1;
489             p_ipos[i_line_len - 1] = '\0';
490         }
491         else
492             p_ipos[i_line_len] = '\0';
493
494         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
495                         p_obuf - p_opos + i_obuf_len, p_ipos );
496         p_ipos += i_line_len + 1;
497     }
498
499     /* XXX: the CRC is OPTIONAL, really require it ? */
500     if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' )
501         return 0;
502
503     uint8_t p_crc[3];
504     if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 )
505         return 0;
506
507     long l_crc = crc_octets( p_obuf, p_opos - p_obuf );
508     long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2];
509
510     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
511 }
512
513 /*
514  * Download the signature associated to a document or a binary file.
515  * We're given the file's url, we just append ".asc" to it and download
516  */
517 static int download_signature(  vlc_object_t *p_this,
518                                 signature_packet_t *p_sig,
519                                 const char *psz_url )
520 {
521     char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */
522     if( !psz_sig )
523         return VLC_ENOMEM;
524
525     strcpy( psz_sig, psz_url );
526     strcat( psz_sig, ".asc" );
527
528     stream_t *p_stream = stream_UrlNew( p_this, psz_sig );
529     free( psz_sig );
530
531     if( !p_stream )
532         return VLC_ENOMEM;
533
534     int64_t i_size = stream_Size( p_stream );
535
536     msg_Dbg( p_this, "Downloading signature (%"PRId64" bytes)", i_size );
537     uint8_t *p_buf = (uint8_t*)malloc( i_size );
538     if( !p_buf )
539     {
540         stream_Delete( p_stream );
541         return VLC_ENOMEM;
542     }
543
544     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
545
546     stream_Delete( p_stream );
547
548     if( i_read != (int)i_size )
549     {
550         msg_Dbg( p_this,
551             "Couldn't download full signature (only %d bytes)", i_read );
552         free( p_buf );
553         return VLC_EGENERIC;
554     }
555
556     if( (uint8_t)*p_buf < 0x80 ) /* ASCII */
557     {
558         msg_Dbg( p_this, "Unarmoring signature" );
559
560         uint8_t* p_unarmored = (uint8_t*) malloc( ( i_size * 3 ) / 4 + 1 );
561         if( !p_unarmored )
562         {
563             free( p_buf );
564             return VLC_EGENERIC;
565         }
566
567         int i_bytes = pgp_unarmor( (char*)p_buf, i_size, p_unarmored, i_size );
568         free( p_buf );
569
570         p_buf = p_unarmored;
571         i_size = i_bytes;
572
573         if( i_bytes < 2 )
574         {
575             free( p_buf );
576             msg_Dbg( p_this, "Unarmoring failed : corrupted signature ?" );
577             return VLC_EGENERIC;
578         }
579     }
580
581     if( packet_type( *p_buf ) != SIGNATURE_PACKET )
582     {
583         free( p_buf );
584         msg_Dbg( p_this, "Not a signature: %d", *p_buf );
585         return VLC_EGENERIC;
586     }
587
588     size_t i_header_len = packet_header_len( *p_buf );
589     if( ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ||
590         i_header_len + 1 > (size_t)i_size )
591     {
592         free( p_buf );
593         msg_Dbg( p_this, "Invalid signature packet header" );
594         return VLC_EGENERIC;
595     }
596
597     size_t i_len = scalar_number( p_buf+1, i_header_len );
598     if( i_len + i_header_len + 1 != (size_t)i_size )
599     {
600         free( p_buf );
601         msg_Dbg( p_this, "Invalid signature packet" );
602         return VLC_EGENERIC;
603     }
604
605     int i_ret = parse_signature_packet( p_sig, p_buf+1+i_header_len, i_len );
606     free( p_buf );
607     if( i_ret != VLC_SUCCESS )
608     {
609         msg_Dbg( p_this, "Couldn't parse signature" );
610         return i_ret;
611     }
612
613     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
614     {
615         msg_Dbg( p_this, "Invalid signature type: %d", p_sig->type );
616         if( p_sig->version == 4 )
617         {
618             free( p_sig->specific.v4.hashed_data );
619             free( p_sig->specific.v4.unhashed_data );
620         }
621         return VLC_EGENERIC;
622     }
623
624     return VLC_SUCCESS;
625 }
626
627 /*
628  * Verify an OpenPGP signature made on some SHA-1 hash, with some DSA public key
629  */
630 static int verify_signature( uint8_t *p_r, uint8_t *p_s,
631         public_key_packet_t *p_key, uint8_t *p_hash )
632 {
633     /* the data to be verified (a SHA-1 hash) */
634     const char *hash_sexp_s = "(data(flags raw)(value %m))";
635     /* the public key */
636     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
637     /* the signature */
638     const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))";
639
640     size_t erroff;
641     gcry_mpi_t p, q, g, y, r, s, hash;
642     p = q = g = y = r = s = hash = NULL;
643     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
644     key_sexp = hash_sexp = sig_sexp = NULL;
645
646     int i_p_len = mpi_len( p_key->p );
647     int i_q_len = mpi_len( p_key->q );
648     int i_g_len = mpi_len( p_key->g );
649     int i_y_len = mpi_len( p_key->y );
650     if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->p + 2, i_p_len, NULL ) ||
651         gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->q + 2, i_q_len, NULL ) ||
652         gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->g + 2, i_g_len, NULL ) ||
653         gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->y + 2, i_y_len, NULL ) ||
654         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
655         goto problem;
656
657     int i_r_len = mpi_len( p_r );
658     int i_s_len = mpi_len( p_s );
659     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
660         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
661         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
662         goto problem;
663
664     int i_hash_len = 20;
665     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
666         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
667         goto problem;
668
669     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
670         goto problem;
671
672     return VLC_SUCCESS;
673
674 problem:
675     if( p ) gcry_mpi_release( p );
676     if( q ) gcry_mpi_release( q );
677     if( g ) gcry_mpi_release( g );
678     if( y ) gcry_mpi_release( y );
679     if( r ) gcry_mpi_release( r );
680     if( s ) gcry_mpi_release( s );
681     if( hash ) gcry_mpi_release( hash );
682     if( key_sexp ) gcry_sexp_release( key_sexp );
683     if( sig_sexp ) gcry_sexp_release( sig_sexp );
684     if( hash_sexp ) gcry_sexp_release( hash_sexp );
685     return VLC_EGENERIC;
686 }
687
688 /*
689  * fill a public_key_t with public key data, including:
690  *   * public key packet
691  *   * signature packet issued by key which long id is p_sig_issuer
692  *   * user id packet
693  */
694 static int parse_public_key( const uint8_t *p_key_data, size_t i_key_len,
695                              public_key_t *p_key, const uint8_t *p_sig_issuer )
696 {
697     uint8_t *pos = (uint8_t*) p_key_data;
698     uint8_t *max_pos = pos + i_key_len;
699
700     int i_status = 0;
701 #define PUBLIC_KEY_FOUND    0x01
702 #define USER_ID_FOUND       0x02
703 #define SIGNATURE_FOUND     0X04
704
705     uint8_t *p_key_unarmored = NULL;
706
707     p_key->psz_username = NULL;
708     p_key->sig.specific.v4.hashed_data = NULL;
709     p_key->sig.specific.v4.unhashed_data = NULL;
710
711     if( !( *pos & 0x80 ) )
712     {   /* first byte is ASCII, unarmoring */
713         p_key_unarmored = (uint8_t*)malloc( i_key_len );
714         if( !p_key_unarmored )
715             return VLC_ENOMEM;
716         int i_len = pgp_unarmor( (char*)p_key_data, i_key_len,
717                                  p_key_unarmored, i_key_len );
718
719         if( i_len == 0 )
720             goto error;
721
722         pos = p_key_unarmored;
723         max_pos = pos + i_len;
724     }
725
726     while( pos < max_pos )
727     {
728         if( !(*pos & 0x80) || *pos & 0x40 )
729             goto error;
730
731         int i_type = packet_type( *pos );
732
733         int i_header_len = packet_header_len( *pos++ );
734         if( pos + i_header_len > max_pos ||
735             ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) )
736             goto error;
737
738         int i_packet_len = scalar_number( pos, i_header_len );
739         pos += i_header_len;
740
741         if( pos + i_packet_len > max_pos )
742             goto error;
743
744         switch( i_type )
745         {
746             case PUBLIC_KEY_PACKET:
747                 i_status |= PUBLIC_KEY_FOUND;
748                 if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS )
749                     goto error;
750                 break;
751
752             case SIGNATURE_PACKET: /* we accept only v4 signatures here */
753                 if( i_status & SIGNATURE_FOUND || !p_sig_issuer )
754                     break;
755                 int i_ret = parse_signature_packet( &p_key->sig, pos,
756                                                     i_packet_len );
757                 if( i_ret == VLC_SUCCESS )
758                 {
759                     if( p_key->sig.version != 4 )
760                         break;
761                     if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) )
762                     {
763                         free( p_key->sig.specific.v4.hashed_data );
764                         free( p_key->sig.specific.v4.unhashed_data );
765                         p_key->sig.specific.v4.hashed_data = NULL;
766                         p_key->sig.specific.v4.unhashed_data = NULL;
767                         break;
768                     }
769                     i_status |= SIGNATURE_FOUND;
770                 }
771                 break;
772
773             case USER_ID_PACKET:
774                 if( p_key->psz_username ) /* save only the first User ID */
775                     break;
776                 i_status |= USER_ID_FOUND;
777                 p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1);
778                 if( !p_key->psz_username )
779                     goto error;
780
781                 memcpy( p_key->psz_username, pos, i_packet_len );
782                 p_key->psz_username[i_packet_len] = '\0';
783                 break;
784
785             default:
786                 break;
787         }
788         pos += i_packet_len;
789     }
790     free( p_key_unarmored );
791
792     if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) )
793         return VLC_EGENERIC;
794
795     if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) )
796         return VLC_EGENERIC;
797
798     return VLC_SUCCESS;
799
800 error:
801     if( p_key->sig.version == 4 )
802     {
803         free( p_key->sig.specific.v4.hashed_data );
804         free( p_key->sig.specific.v4.unhashed_data );
805     }
806     free( p_key->psz_username );
807     free( p_key_unarmored );
808     return VLC_EGENERIC;
809 }
810
811 /*
812  * return a sha1 hash of a file
813  */
814 static uint8_t *hash_sha1_from_file( const char *psz_file,
815                             signature_packet_t *p_sig )
816 {
817     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
818         return NULL;
819
820     FILE *f = utf8_fopen( psz_file, "r" );
821     if( !f )
822         return NULL;
823
824     uint8_t buffer[4096];
825
826     gcry_md_hd_t hd;
827     if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
828     {
829         fclose( f );
830         return NULL;
831     }
832
833     size_t i_read;
834     while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 )
835         gcry_md_write( hd, buffer, i_read );
836
837     if( p_sig->version == 3 )
838     {
839         gcry_md_putc( hd, p_sig->type );
840         gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 );
841     }
842     else if( p_sig->version == 4 )
843     {
844         gcry_md_putc( hd, p_sig->version );
845         gcry_md_putc( hd, p_sig->type );
846         gcry_md_putc( hd, p_sig->public_key_algo );
847         gcry_md_putc( hd, p_sig->digest_algo );
848         gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 );
849         size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
850         gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len );
851
852         gcry_md_putc( hd, 0x04 );
853         gcry_md_putc( hd, 0xFF );
854
855         i_len += 6; /* hashed data + 6 bytes header */
856
857         gcry_md_putc( hd, (i_len >> 24) & 0xff );
858         gcry_md_putc( hd, (i_len >> 16) & 0xff );
859         gcry_md_putc( hd, (i_len >> 8) & 0xff );
860         gcry_md_putc( hd, (i_len) & 0xff );
861     }
862     else
863     {   /* RFC 4880 only tells about versions 3 and 4 */
864         gcry_md_close( hd );
865         return NULL;
866     }
867
868     fclose( f );
869     gcry_md_final( hd );
870
871     uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, GCRY_MD_SHA1);
872     uint8_t *p_hash = malloc( 20 );
873     if( p_hash )
874         memcpy( p_hash, p_tmp, 20 );
875     gcry_md_close( hd );
876     return p_hash;
877 }
878
879 /*
880  * download a public key (the last one) from videolan server, and parse it
881  */
882 static public_key_t *download_key( vlc_object_t *p_this,
883                     const uint8_t *p_longid, const uint8_t *p_signature_issuer )
884 {
885     char *psz_url;
886     if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc",
887                     p_longid[0], p_longid[1], p_longid[2], p_longid[3],
888                     p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 )
889         return NULL;
890
891     stream_t *p_stream = stream_UrlNew( p_this, psz_url );
892     free( psz_url );
893     if( !p_stream )
894         return NULL;
895
896     int64_t i_size = stream_Size( p_stream );
897     if( i_size < 0 )
898     {
899         stream_Delete( p_stream );
900         return NULL;
901     }
902
903     uint8_t *p_buf = (uint8_t*)malloc( i_size );
904     if( !p_buf )
905     {
906         stream_Delete( p_stream );
907         return NULL;
908     }
909
910     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
911     stream_Delete( p_stream );
912
913     if( i_read != (int)i_size )
914     {
915         msg_Dbg( p_this, "Couldn't read full GPG key" );
916         free( p_buf );
917         return NULL;
918     }
919
920     public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) );
921     if( !p_pkey )
922     {
923         free( p_buf );
924         return NULL;
925     }
926
927     memcpy( p_pkey->longid, p_longid, 8 );
928
929     int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer );
930     free( p_buf );
931
932     if( i_error != VLC_SUCCESS )
933     {
934         msg_Dbg( p_this, "Couldn't parse GPG key" );
935         free( p_pkey );
936         return NULL;
937     }
938
939     return p_pkey;
940 }
941
942 /*
943  * Generate a SHA1 hash on a public key, to verify a signature made on that hash
944  * Note that we need the signature (v4) to compute the hash
945  */
946 static uint8_t *key_sign_hash( public_key_t *p_pkey )
947 {
948     if( p_pkey->sig.version != 4 )
949         return NULL;
950
951     if( p_pkey->sig.type < GENERIC_KEY_SIGNATURE ||
952         p_pkey->sig.type > POSITIVE_KEY_SIGNATURE )
953         return NULL;
954
955     gcry_error_t error = 0;
956     gcry_md_hd_t hd;
957
958     error = gcry_md_open( &hd, GCRY_MD_SHA1, 0 );
959     if( error )
960         return NULL;
961
962     gcry_md_putc( hd, 0x99 );
963
964     size_t i_p_len = mpi_len( p_pkey->key.p );
965     size_t i_g_len = mpi_len( p_pkey->key.g );
966     size_t i_q_len = mpi_len( p_pkey->key.q );
967     size_t i_y_len = mpi_len( p_pkey->key.y );
968
969     size_t i_size = 6 + 2*4 + i_p_len + i_g_len + i_q_len + i_y_len;
970
971     gcry_md_putc( hd, (i_size >> 8) & 0xff );
972     gcry_md_putc( hd, i_size & 0xff );
973
974     gcry_md_putc( hd, p_pkey->key.version );
975     gcry_md_write( hd, p_pkey->key.timestamp, 4 );
976     gcry_md_putc( hd, p_pkey->key.algo );
977
978     gcry_md_write( hd, (uint8_t*)&p_pkey->key.p, 2 );
979     gcry_md_write( hd, (uint8_t*)&p_pkey->key.p + 2, i_p_len );
980
981     gcry_md_write( hd, (uint8_t*)&p_pkey->key.q, 2 );
982     gcry_md_write( hd, (uint8_t*)&p_pkey->key.q + 2, i_q_len );
983
984     gcry_md_write( hd, (uint8_t*)&p_pkey->key.g, 2 );
985     gcry_md_write( hd, (uint8_t*)&p_pkey->key.g + 2, i_g_len );
986
987     gcry_md_write( hd, (uint8_t*)&p_pkey->key.y, 2 );
988     gcry_md_write( hd, (uint8_t*)&p_pkey->key.y + 2, i_y_len );
989
990     gcry_md_putc( hd, 0xb4 );
991
992     size_t i_len = strlen((char*)p_pkey->psz_username);
993
994     gcry_md_putc( hd, (i_len >> 24) & 0xff );
995     gcry_md_putc( hd, (i_len >> 16) & 0xff );
996     gcry_md_putc( hd, (i_len >> 8) & 0xff );
997     gcry_md_putc( hd, (i_len) & 0xff );
998
999     gcry_md_write( hd, p_pkey->psz_username, i_len );
1000
1001     size_t i_hashed_data_len =
1002         scalar_number( p_pkey->sig.specific.v4.hashed_data_len, 2 );
1003
1004     gcry_md_putc( hd, p_pkey->sig.version );
1005     gcry_md_putc( hd, p_pkey->sig.type );
1006     gcry_md_putc( hd, p_pkey->sig.public_key_algo );
1007     gcry_md_putc( hd, p_pkey->sig.digest_algo );
1008     gcry_md_write( hd, p_pkey->sig.specific.v4.hashed_data_len, 2 );
1009     gcry_md_write( hd, p_pkey->sig.specific.v4.hashed_data, i_hashed_data_len );
1010
1011     gcry_md_putc( hd, 0x04 );
1012     gcry_md_putc( hd, 0xff );
1013
1014     i_hashed_data_len += 6; /* hashed data + 6 bytes header */
1015
1016     gcry_md_putc( hd, (i_hashed_data_len >> 24) & 0xff );
1017     gcry_md_putc( hd, (i_hashed_data_len >> 16) & 0xff );
1018     gcry_md_putc( hd, (i_hashed_data_len >> 8) & 0xff );
1019     gcry_md_putc( hd, (i_hashed_data_len) & 0xff );
1020
1021     gcry_md_final( hd );
1022
1023     uint8_t *p_tmp = gcry_md_read( hd, GCRY_MD_SHA1 );
1024
1025     if( !p_tmp ||
1026         p_tmp[0] != p_pkey->sig.hash_verification[0] ||
1027         p_tmp[1] != p_pkey->sig.hash_verification[1] )
1028     {
1029         gcry_md_close( hd );
1030         return NULL;
1031     }
1032
1033     uint8_t *p_hash = malloc( 20 );
1034     if( p_hash )
1035         memcpy( p_hash, p_tmp, 20 );
1036     gcry_md_close( hd );
1037     return p_hash;
1038 }
1039
1040
1041 /*****************************************************************************
1042  * Update_t functions
1043  *****************************************************************************/
1044
1045 /**
1046  * Create a new update VLC struct
1047  *
1048  * \param p_this the calling vlc_object
1049  * \return pointer to new update_t or NULL
1050  */
1051 update_t *__update_New( vlc_object_t *p_this )
1052 {
1053     update_t *p_update;
1054     assert( p_this );
1055
1056     p_update = (update_t *)malloc( sizeof( update_t ) );
1057     if( !p_update ) return NULL;
1058
1059     vlc_mutex_init( &p_update->lock );
1060
1061     p_update->p_libvlc = p_this->p_libvlc;
1062
1063     p_update->release.psz_url = NULL;
1064     p_update->release.psz_desc = NULL;
1065
1066     p_update->p_download = NULL;
1067     p_update->p_check = NULL;
1068
1069     p_update->p_pkey = NULL;
1070     vlc_gcrypt_init();
1071
1072     return p_update;
1073 }
1074
1075 /**
1076  * Delete an update_t struct
1077  *
1078  * \param p_update update_t* pointer
1079  * \return nothing
1080  */
1081 void update_Delete( update_t *p_update )
1082 {
1083     assert( p_update );
1084
1085     if( p_update->p_check )
1086     {
1087         assert( !p_update->p_download );
1088         vlc_object_kill( p_update->p_check );
1089         vlc_thread_join( p_update->p_check );
1090         vlc_object_release( p_update->p_check );
1091     }
1092     else if( p_update->p_download )
1093     {
1094         vlc_object_kill( p_update->p_download );
1095         vlc_thread_join( p_update->p_download );
1096         vlc_object_release( p_update->p_download );
1097     }
1098
1099     vlc_mutex_destroy( &p_update->lock );
1100
1101     free( p_update->release.psz_url );
1102     free( p_update->release.psz_desc );
1103     free( p_update->p_pkey );
1104
1105     free( p_update );
1106 }
1107
1108 /**
1109  * Empty the release struct
1110  *
1111  * \param p_update update_t* pointer
1112  * \return nothing
1113  */
1114 static void EmptyRelease( update_t *p_update )
1115 {
1116     p_update->release.i_major = 0;
1117     p_update->release.i_minor = 0;
1118     p_update->release.i_revision = 0;
1119
1120     FREENULL( p_update->release.psz_url );
1121     FREENULL( p_update->release.psz_desc );
1122 }
1123
1124 /**
1125  * Get the update file and parse it
1126  * p_update has to be locked when calling this function
1127  *
1128  * \param p_update pointer to update struct
1129  * \return true if the update is valid and authenticated
1130  */
1131 static bool GetUpdateFile( update_t *p_update )
1132 {
1133     stream_t *p_stream = NULL;
1134     int i_major = 0;
1135     int i_minor = 0;
1136     int i_revision = 0;
1137     unsigned char extra;
1138     char *psz_version_line = NULL;
1139
1140     p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
1141     if( !p_stream )
1142     {
1143         msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
1144                  UPDATE_VLC_STATUS_URL );
1145         goto error;
1146     }
1147
1148     /* Start reading the status file */
1149     if( !( psz_version_line = stream_ReadLine( p_stream ) ) )
1150     {
1151         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version",
1152                  UPDATE_VLC_STATUS_URL );
1153         goto error;
1154     }
1155
1156     /* first line : version number */
1157     p_update->release.extra = 0;
1158     switch( sscanf( psz_version_line, "%i.%i.%i%c",
1159                     &i_major, &i_minor, &i_revision, &extra ) )
1160     {
1161         case 4:
1162             p_update->release.extra = extra;
1163         case 3:
1164             p_update->release.i_major = i_major;
1165             p_update->release.i_minor = i_minor;
1166             p_update->release.i_revision = i_revision;
1167             break;
1168         default:
1169             msg_Err( p_update->p_libvlc, "Update version false formated" );
1170             goto error;
1171     }
1172
1173     /* second line : URL */
1174     if( !( p_update->release.psz_url = stream_ReadLine( p_stream ) ) )
1175     {
1176         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing",
1177                  UPDATE_VLC_STATUS_URL );
1178         goto error;
1179     }
1180
1181     /* Remaining data : description */
1182     int i_read = stream_Size( p_stream ) - stream_Tell( p_stream );
1183     if( i_read <= 0 )
1184     {
1185         msg_Err( p_update->p_libvlc,
1186                 "Update file %s is corrupted: description missing",
1187                 UPDATE_VLC_STATUS_URL );
1188         goto error;
1189     }
1190
1191     p_update->release.psz_desc = (char*) malloc( i_read + 1 );
1192     if( !p_update->release.psz_desc )
1193         goto error;
1194
1195     if( stream_Read( p_stream, p_update->release.psz_desc, i_read ) != i_read )
1196     {
1197         msg_Err( p_update->p_libvlc, "Couldn't download update file %s",
1198                 UPDATE_VLC_STATUS_URL );
1199         goto error;
1200     }
1201     p_update->release.psz_desc[i_read] = '\0';
1202
1203     stream_Delete( p_stream );
1204     p_stream = NULL;
1205
1206     /* Now that we know the status is valid, we must download its signature
1207      * to authenticate it */
1208     signature_packet_t sign;
1209     if( download_signature( VLC_OBJECT( p_update->p_libvlc ), &sign,
1210             UPDATE_VLC_STATUS_URL ) != VLC_SUCCESS )
1211     {
1212         msg_Err( p_update->p_libvlc, "Couldn't download signature of status file" );
1213         goto error;
1214     }
1215
1216     if( sign.type != BINARY_SIGNATURE && sign.type != TEXT_SIGNATURE )
1217     {
1218         msg_Err( p_update->p_libvlc, "Invalid signature type" );
1219         goto error;
1220     }
1221
1222     p_update->p_pkey = (public_key_t*)malloc( sizeof( public_key_t ) );
1223     if( !p_update->p_pkey )
1224         goto error;
1225
1226     if( parse_public_key( videolan_public_key, sizeof( videolan_public_key ),
1227                         p_update->p_pkey, NULL ) != VLC_SUCCESS )
1228     {
1229         msg_Err( p_update->p_libvlc, "Couldn't parse embedded public key, something went really wrong..." );
1230         FREENULL( p_update->p_pkey );
1231         goto error;
1232     }
1233
1234     memcpy( p_update->p_pkey->longid, videolan_public_key_longid, 8 );
1235
1236     if( memcmp( sign.issuer_longid, p_update->p_pkey->longid , 8 ) != 0 )
1237     {
1238         msg_Dbg( p_update->p_libvlc, "Need to download the GPG key" );
1239         public_key_t *p_new_pkey = download_key(
1240                 VLC_OBJECT(p_update->p_libvlc),
1241                 sign.issuer_longid, videolan_public_key_longid );
1242         if( !p_new_pkey )
1243         {
1244             msg_Err( p_update->p_libvlc, "Couldn't download GPG key" );
1245             FREENULL( p_update->p_pkey );
1246             goto error;
1247         }
1248
1249         uint8_t *p_hash = key_sign_hash( p_new_pkey );
1250         if( !p_hash )
1251         {
1252             msg_Err( p_update->p_libvlc, "Failed to hash signature" );
1253             free( p_new_pkey );
1254             FREENULL( p_update->p_pkey );
1255             goto error;
1256         }
1257
1258         if( verify_signature( p_new_pkey->sig.r, p_new_pkey->sig.s,
1259                     &p_update->p_pkey->key, p_hash ) == VLC_SUCCESS )
1260         {
1261             free( p_hash );
1262             msg_Info( p_update->p_libvlc, "Key authenticated" );
1263             free( p_update->p_pkey );
1264             p_update->p_pkey = p_new_pkey;
1265         }
1266         else
1267         {
1268             free( p_hash );
1269             msg_Err( p_update->p_libvlc, "Key signature invalid !\n" );
1270             goto error;
1271         }
1272     }
1273
1274     gcry_md_hd_t hd;
1275     if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
1276         goto error_hd;
1277
1278     gcry_md_write( hd, psz_version_line, strlen( psz_version_line ) );
1279     FREENULL( psz_version_line );
1280     if( sign.type == TEXT_SIGNATURE )
1281         gcry_md_putc( hd, '\r' );
1282     gcry_md_putc( hd, '\n' );
1283     gcry_md_write( hd, p_update->release.psz_url,
1284                         strlen( p_update->release.psz_url ) );
1285     if( sign.type == TEXT_SIGNATURE )
1286         gcry_md_putc( hd, '\r' );
1287     gcry_md_putc( hd, '\n' );
1288
1289     char *psz_desc = p_update->release.psz_desc;
1290     while( *psz_desc )
1291     {
1292         size_t i_len = strcspn( psz_desc, "\r\n" );
1293         if( !i_len )
1294             break;
1295
1296         gcry_md_write( hd, psz_desc, i_len );
1297         if( sign.type == TEXT_SIGNATURE )
1298             gcry_md_putc( hd, '\r' );
1299         gcry_md_putc( hd, '\n' );
1300
1301         psz_desc += i_len;
1302         while( *psz_desc == '\r' || *psz_desc == '\n' )
1303             psz_desc++;
1304     }
1305
1306     if( sign.version == 3 )
1307     {
1308         gcry_md_putc( hd, sign.type );
1309         gcry_md_write( hd, &sign.specific.v3.timestamp, 4 );
1310     }
1311     else if( sign.version == 4 )
1312     {
1313         gcry_md_putc( hd, sign.version );
1314         gcry_md_putc( hd, sign.type );
1315         gcry_md_putc( hd, sign.public_key_algo );
1316         gcry_md_putc( hd, sign.digest_algo );
1317         gcry_md_write( hd, sign.specific.v4.hashed_data_len, 2 );
1318         size_t i_len = scalar_number( sign.specific.v4.hashed_data_len, 2 );
1319         gcry_md_write( hd, sign.specific.v4.hashed_data, i_len );
1320         gcry_md_putc( hd, 0x04 );
1321         gcry_md_putc( hd, 0xFF );
1322
1323         i_len += 6; /* hashed data + 6 bytes header */
1324
1325         gcry_md_putc( hd, (i_len >> 24) & 0xff );
1326         gcry_md_putc( hd, (i_len >> 16) & 0xff );
1327         gcry_md_putc( hd, (i_len >> 8) & 0xff );
1328         gcry_md_putc( hd, (i_len) & 0xff );
1329     }
1330     else
1331     {   /* RFC 4880 only tells about versions 3 and 4 */
1332         msg_Warn( p_update->p_libvlc, "Invalid signature version %d",
1333                 sign.version);
1334         goto error_hd;
1335     }
1336
1337     gcry_md_final( hd );
1338
1339     uint8_t *p_hash = gcry_md_read( hd, GCRY_MD_SHA1 );
1340
1341     if( p_hash[0] != sign.hash_verification[0] ||
1342         p_hash[1] != sign.hash_verification[1] )
1343     {
1344         msg_Warn( p_update->p_libvlc, "Bad SHA1 hash for status file" );
1345         goto error_hd;
1346     }
1347
1348     if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
1349             != VLC_SUCCESS )
1350     {
1351         msg_Err( p_update->p_libvlc, "BAD SIGNATURE for status file" );
1352         goto error_hd;
1353     }
1354     else
1355     {
1356         msg_Info( p_update->p_libvlc, "Status file authenticated" );
1357         gcry_md_close( hd );
1358         return true;
1359     }
1360
1361 error_hd:
1362     gcry_md_close( hd );
1363 error:
1364     if( p_stream )
1365         stream_Delete( p_stream );
1366     free( psz_version_line );
1367     return false;
1368 }
1369
1370 static void* update_CheckReal( vlc_object_t *p_this );
1371
1372 /**
1373  * Check for updates
1374  *
1375  * \param p_update pointer to update struct
1376  * \param pf_callback pointer to a function to call when the update_check is finished
1377  * \param p_data pointer to some datas to give to the callback
1378  * \returns nothing
1379  */
1380 void update_Check( update_t *p_update, void (*pf_callback)( void*, bool ), void *p_data )
1381 {
1382     assert( p_update );
1383
1384     update_check_thread_t *p_uct =
1385         vlc_custom_create( p_update->p_libvlc, sizeof( *p_uct ),
1386                            VLC_OBJECT_GENERIC, "update check" );
1387     if( !p_uct ) return;
1388
1389     p_uct->p_update = p_update;
1390     p_update->p_check = p_uct;
1391     p_uct->pf_callback = pf_callback;
1392     p_uct->p_data = p_data;
1393
1394     vlc_thread_create( p_uct, "check for update", update_CheckReal,
1395                        VLC_THREAD_PRIORITY_LOW );
1396 }
1397
1398 void* update_CheckReal( vlc_object_t* p_this )
1399 {
1400     update_check_thread_t *p_uct = (update_check_thread_t *)p_this;
1401     bool b_ret;
1402     int canc;
1403
1404     canc = vlc_savecancel ();
1405     vlc_mutex_lock( &p_uct->p_update->lock );
1406
1407     EmptyRelease( p_uct->p_update );
1408     b_ret = GetUpdateFile( p_uct->p_update );
1409     vlc_mutex_unlock( &p_uct->p_update->lock );
1410
1411     if( p_uct->pf_callback )
1412         (p_uct->pf_callback)( p_uct->p_data, b_ret );
1413
1414     vlc_restorecancel (canc);
1415     return NULL;
1416 }
1417
1418 /**
1419  * Compare a given release's version number to the current VLC's one
1420  *
1421  * \param p_update structure
1422  * \return true if we have to upgrade to the given version to be up to date
1423  */
1424 static bool is_strictly_greater( int * a, int * b, int n)
1425 {
1426     if( n <= 0 ) return false;
1427     if(a[0] > b[0] ) return true;
1428     if(a[0] == b[0] ) return is_strictly_greater( a+1, b+1, n-1 );
1429     /* a[0] < b[0] */ return false;
1430 }
1431
1432 bool update_NeedUpgrade( update_t *p_update )
1433 {
1434     assert( p_update );
1435
1436     int current_version[] = {
1437         *PACKAGE_VERSION_MAJOR - '0',
1438         *PACKAGE_VERSION_MINOR - '0',
1439         *PACKAGE_VERSION_REVISION - '0',
1440         *PACKAGE_VERSION_EXTRA
1441     };
1442     int latest_version[] = {
1443         p_update->release.i_major,
1444         p_update->release.i_minor,
1445         p_update->release.i_revision,
1446         p_update->release.extra
1447     };
1448
1449     return is_strictly_greater( latest_version, current_version, 4 );
1450 }
1451
1452 /**
1453  * Convert a long int size in bytes to a string
1454  *
1455  * \param l_size the size in bytes
1456  * \return the size as a string
1457  */
1458 static char *size_str( long int l_size )
1459 {
1460     char *psz_tmp = NULL;
1461     int i_retval = 0;
1462     if( l_size >> 30 )
1463         i_retval = asprintf( &psz_tmp, _("%.1f GB"), (float)l_size/(1<<30) );
1464     else if( l_size >> 20 )
1465         i_retval = asprintf( &psz_tmp, _("%.1f MB"), (float)l_size/(1<<20) );
1466     else if( l_size >> 10 )
1467         i_retval = asprintf( &psz_tmp, _("%.1f kB"), (float)l_size/(1<<10) );
1468     else
1469         i_retval = asprintf( &psz_tmp, _("%ld B"), l_size );
1470
1471     return i_retval == -1 ? NULL : psz_tmp;
1472 }
1473
1474 void update_WaitDownload( update_t *p_update )
1475 {
1476     if(p_update->p_download)
1477         vlc_thread_join( p_update->p_download );
1478     vlc_object_release( p_update->p_download );
1479     p_update->p_download = NULL;
1480 }
1481
1482 static void* update_DownloadReal( vlc_object_t *p_this );
1483
1484 /**
1485  * Download the file given in the update_t
1486  *
1487  * \param p_update structure
1488  * \param destination to store the download file
1489  *        This can be an existing dir, a (non)existing target fullpath filename or
1490  *        NULL for the current working dir.
1491  * \return nothing
1492  */
1493 void update_Download( update_t *p_update, const char *destination )
1494 {
1495     assert( p_update );
1496
1497     update_download_thread_t *p_udt =
1498         vlc_custom_create( p_update->p_libvlc, sizeof( *p_udt ),
1499                            VLC_OBJECT_GENERIC, "update download" );
1500     if( !p_udt )
1501         return;
1502
1503     p_udt->p_update = p_update;
1504     p_update->p_download = p_udt;
1505     p_udt->psz_destination = destination ? strdup( destination ) : NULL;
1506
1507     vlc_thread_create( p_udt, "download update", update_DownloadReal,
1508                        VLC_THREAD_PRIORITY_LOW );
1509 }
1510
1511 static void* update_DownloadReal( vlc_object_t *p_this )
1512 {
1513     update_download_thread_t *p_udt = (update_download_thread_t *)p_this;
1514     interaction_dialog_t *p_progress = 0;
1515     long int l_size;
1516     long int l_downloaded = 0;
1517     float f_progress;
1518     char *psz_status = NULL;
1519     char *psz_downloaded = NULL;
1520     char *psz_size = NULL;
1521     char *psz_destfile = NULL;
1522     char *psz_tmpdestfile = NULL;
1523
1524     FILE *p_file = NULL;
1525     struct stat p_stat;
1526     stream_t *p_stream = NULL;
1527     void* p_buffer = NULL;
1528     int i_read;
1529     int canc;
1530
1531     update_t *p_update = p_udt->p_update;
1532     char *psz_destination = p_udt->psz_destination;
1533
1534     msg_Dbg( p_udt, "Opening Stream '%s'", p_update->release.psz_url );
1535     canc = vlc_savecancel ();
1536
1537     /* Open the stream */
1538     p_stream = stream_UrlNew( p_udt, p_update->release.psz_url );
1539     if( !p_stream )
1540     {
1541         msg_Err( p_udt, "Failed to open %s for reading", p_update->release.psz_url );
1542         goto end;
1543     }
1544
1545     /* Get the stream size */
1546     l_size = stream_Size( p_stream );
1547
1548     /* Get the file name and open it*/
1549     psz_tmpdestfile = strrchr( p_update->release.psz_url, '/' );
1550     if( !psz_tmpdestfile )
1551     {
1552         msg_Err( p_udt, "The URL %s is badly formated",
1553                  p_update->release.psz_url );
1554         goto end;
1555     }
1556     psz_tmpdestfile++;
1557
1558     if( utf8_stat( psz_destination, &p_stat) == 0 && (p_stat.st_mode & S_IFDIR) )
1559     {
1560         if( asprintf( &psz_destfile, "%s%c%s", psz_destination, DIR_SEP_CHAR, psz_tmpdestfile ) == -1 )
1561             goto end;
1562     }
1563     else if( psz_destination )
1564         psz_destfile = strdup( psz_destination );
1565     else
1566         psz_destfile = strdup( psz_tmpdestfile );
1567
1568     p_file = utf8_fopen( psz_destfile, "w" );
1569     if( !p_file )
1570     {
1571         msg_Err( p_udt, "Failed to open %s for writing", psz_destfile );
1572         intf_UserFatal( p_udt, true, _("Saving file failed"),
1573             _("Failed to open \"%s\" for writing"),
1574              psz_destfile );
1575         goto end;
1576     }
1577
1578     /* Create a buffer and fill it with the downloaded file */
1579     p_buffer = (void *)malloc( 1 << 10 );
1580     if( !p_buffer )
1581     {
1582         msg_Err( p_udt, "Can't malloc (1 << 10) bytes! download cancelled." );
1583         goto end;
1584     }
1585
1586     msg_Dbg( p_udt, "Downloading Stream '%s'", p_update->release.psz_url );
1587
1588     psz_size = size_str( l_size );
1589     if( asprintf( &psz_status, _("%s\nDownloading... %s/%s %.1f%% done"),
1590         p_update->release.psz_url, "0.0", psz_size, 0.0 ) != -1 )
1591     {
1592         p_progress = intf_UserProgress( p_udt, _( "Downloading ..."),
1593                                         psz_status, 0.0, 0 );
1594         free( psz_status );
1595     }
1596
1597     vlc_object_lock( p_udt );
1598     while( vlc_object_alive( p_udt ) &&
1599            ( i_read = stream_Read( p_stream, p_buffer, 1 << 10 ) ) &&
1600            !intf_ProgressIsCancelled( p_udt, p_progress ) )
1601     {
1602         vlc_object_unlock( p_udt );
1603         if( fwrite( p_buffer, i_read, 1, p_file ) < 1 )
1604         {
1605             msg_Err( p_udt, "Failed to write into %s", psz_destfile );
1606             break;
1607         }
1608
1609         l_downloaded += i_read;
1610         psz_downloaded = size_str( l_downloaded );
1611         f_progress = 100.0*(float)l_downloaded/(float)l_size;
1612
1613         if( asprintf( &psz_status, _( "%s\nDownloading... %s/%s %.1f%% done" ),
1614                       p_update->release.psz_url, psz_downloaded, psz_size,
1615                       f_progress ) != -1 )
1616         {
1617             intf_ProgressUpdate( p_udt, p_progress, psz_status, f_progress, 0 );
1618             free( psz_status );
1619         }
1620         free( psz_downloaded );
1621         vlc_object_lock( p_udt );
1622     }
1623
1624     /* Finish the progress bar or delete the file if the user had canceled */
1625     fclose( p_file );
1626     p_file = NULL;
1627
1628     if( vlc_object_alive( p_udt ) &&
1629         !intf_ProgressIsCancelled( p_udt, p_progress ) )
1630     {
1631         vlc_object_unlock( p_udt );
1632         if( asprintf( &psz_status, _("%s\nDone %s (100.0%%)"),
1633             p_update->release.psz_url, psz_size ) != -1 )
1634         {
1635             intf_ProgressUpdate( p_udt, p_progress, psz_status, 100.0, 0 );
1636             p_progress = NULL
1637             free( psz_status );
1638         }
1639     }
1640     else
1641     {
1642         vlc_object_unlock( p_udt );
1643         utf8_unlink( psz_destfile );
1644         goto end;
1645     }
1646
1647     signature_packet_t sign;
1648     if( download_signature( VLC_OBJECT( p_udt ), &sign,
1649             p_update->release.psz_url ) != VLC_SUCCESS )
1650     {
1651         utf8_unlink( psz_destfile );
1652
1653         intf_UserFatal( p_udt, true, _("File could not be verified"),
1654             _("It was not possible to download a cryptographic signature for "
1655               "the downloaded file \"%s\". Thus, it was deleted."),
1656             psz_destfile );
1657         msg_Err( p_udt, "Couldn't download signature of downloaded file" );
1658         goto end;
1659     }
1660
1661     if( memcmp( sign.issuer_longid, p_update->p_pkey->longid, 8 ) )
1662     {
1663         utf8_unlink( psz_destfile );
1664         msg_Err( p_udt, "Invalid signature issuer" );
1665         intf_UserFatal( p_udt, true, _("Invalid signature"),
1666             _("The cryptographic signature for the downloaded file \"%s\" was "
1667               "invalid and could not be used to securely verify it. Thus, the "
1668               "file was deleted."),
1669             psz_destfile );
1670         goto end;
1671     }
1672
1673     if( sign.type != BINARY_SIGNATURE )
1674     {
1675         utf8_unlink( psz_destfile );
1676         msg_Err( p_udt, "Invalid signature type" );
1677         intf_UserFatal( p_udt, true, _("Invalid signature"),
1678             _("The cryptographic signature for the downloaded file \"%s\" was "
1679               "invalid and could not be used to securely verify it. Thus, the "
1680               "file was deleted."),
1681             psz_destfile );
1682         goto end;
1683     }
1684
1685     uint8_t *p_hash = hash_sha1_from_file( psz_destfile, &sign );
1686     if( !p_hash )
1687     {
1688         msg_Err( p_udt, "Unable to hash %s", psz_destfile );
1689         utf8_unlink( psz_destfile );
1690         intf_UserFatal( p_udt, true, _("File not verifiable"),
1691             _("It was not possible to securely verify the downloaded file"
1692               " \"%s\". Thus, it was deleted."),
1693             psz_destfile );
1694
1695         goto end;
1696     }
1697
1698     if( p_hash[0] != sign.hash_verification[0] ||
1699         p_hash[1] != sign.hash_verification[1] )
1700     {
1701         utf8_unlink( psz_destfile );
1702         intf_UserFatal( p_udt, true, _("File corrupted"),
1703             _("Downloaded file \"%s\" was corrupted. Thus, it was deleted."),
1704              psz_destfile );
1705         msg_Err( p_udt, "Bad SHA1 hash for %s", psz_destfile );
1706         free( p_hash );
1707         goto end;
1708     }
1709
1710     if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
1711             != VLC_SUCCESS )
1712     {
1713         utf8_unlink( psz_destfile );
1714         intf_UserFatal( p_udt, true, _("File corrupted"),
1715             _("Downloaded file \"%s\" was corrupted. Thus, it was deleted."),
1716              psz_destfile );
1717         msg_Err( p_udt, "BAD SIGNATURE for %s", psz_destfile );
1718         free( p_hash );
1719         goto end;
1720     }
1721
1722     msg_Info( p_udt, "%s authenticated", psz_destfile );
1723     free( p_hash );
1724
1725 end:
1726     if( p_progress )
1727     {
1728         intf_ProgressUpdate( p_udt, p_progress, _("Cancelled"), 100.0, 0 );
1729     }
1730     if( p_stream )
1731         stream_Delete( p_stream );
1732     if( p_file )
1733         fclose( p_file );
1734     free( psz_destfile );
1735     free( p_buffer );
1736     free( psz_size );
1737
1738     free( p_udt->psz_destination );
1739     p_udt->p_update->p_download = NULL;
1740
1741     vlc_object_release( p_udt );
1742     vlc_restorecancel( canc );
1743     return NULL;
1744 }
1745
1746 update_release_t *update_GetRelease( update_t *p_update )
1747 {
1748     return &p_update->release;
1749 }
1750
1751 #else
1752 update_t *__update_New( vlc_object_t *p_this )
1753 {
1754     (void)p_this;
1755     return NULL;
1756 }
1757
1758 void update_Delete( update_t *p_update )
1759 {
1760     (void)p_update;
1761 }
1762
1763 void update_Check( update_t *p_update, void (*pf_callback)( void*, bool ),
1764                    void *p_data )
1765 {
1766     (void)p_update; (void)pf_callback; (void)p_data;
1767 }
1768
1769 bool update_NeedUpgrade( update_t *p_update )
1770 {
1771     (void)p_update;
1772     return false;
1773 }
1774
1775 void update_WaitDownload( update_t *p_update )
1776 {
1777     (void)p_update;
1778 }
1779
1780 void update_Download( update_t *p_update, const char *psz_destdir )
1781 {
1782     (void)p_update; (void)psz_destdir;
1783 }
1784
1785 update_release_t *update_GetRelease( update_t *p_update )
1786 {
1787     (void)p_update;
1788     return NULL;
1789 }
1790 #endif