]> git.sesse.net Git - vlc/blob - src/misc/update.c
update check: Initialize gcrypt threading - fixes #1483
[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  * XXX: should use v4 signatures for binary files (already used for public key)
27  */
28 /**
29  *   \file
30  *   This file contains functions related to VLC update management
31  */
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <vlc/vlc.h>
42
43 #ifdef UPDATE_CHECK
44
45 #include <assert.h>
46
47 #include <vlc_update.h>
48 #include <vlc_pgpkey.h>
49 #include <vlc_stream.h>
50 #include <vlc_interface.h>
51 #include <vlc_gcrypt.h>
52
53
54 /*****************************************************************************
55  * Misc defines
56  *****************************************************************************/
57
58 /*
59  * Here is the format of these "status files" :
60  * First line is the last version: "X.Y.Ze" where:
61  *      * X is the major number
62  *      * Y is the minor number
63  *      * Z is the revision number
64  *      * e is an OPTIONAL extra letter
65  *      * AKA "0.8.6d" or "0.9.0"
66  * Second line is an url of the binary for this last version
67  * Third line is a description of the update (it MAY be extended to several lines, but for now it is only one line)
68  */
69
70 #if defined( UNDER_CE )
71 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
72 #elif defined( WIN32 )
73 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
74 #elif defined( __APPLE__ )
75 #   if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
76 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-ppc"
77 #   else
78 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
79 #   endif
80 #elif defined( SYS_BEOS )
81 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
82 #else
83 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
84 #endif
85
86
87 /*****************************************************************************
88  * Local Prototypes
89  *****************************************************************************/
90 static void EmptyRelease( update_t *p_update );
91 static bool GetUpdateFile( update_t *p_update );
92 static char * size_str( long int l_size );
93
94
95 /*****************************************************************************
96  * OpenPGP functions
97  *****************************************************************************/
98
99 #define packet_type( c ) ( ( c & 0x3c ) >> 2 )      /* 0x3C = 00111100 */
100 #define packet_header_len( c ) ( ( c & 0x03 ) + 1 ) /* number of bytes in a packet header */
101
102 static inline int scalar_number( uint8_t *p, int header_len )
103 {
104     if( header_len == 1 )
105         return( p[0] );
106     else if( header_len == 2 )
107         return( (p[0] << 8) + p[1] );
108     else if( header_len == 4 )
109         return( (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3] );
110     else
111         abort();
112 }
113
114 /* number of data bytes in a MPI */
115 #define mpi_len( mpi ) ( ( scalar_number( mpi, 2 ) + 7 ) / 8 )
116
117 /*
118  * fill a public_key_packet_t structure from public key packet data
119  * verify that it is a version 4 public key packet, using DSA
120  */
121 static int parse_public_key_packet( public_key_packet_t *p_key, uint8_t *p_buf,
122                                     size_t i_packet_len )
123 {
124     if( i_packet_len > 418 )
125         return VLC_EGENERIC;
126
127     p_key->version   = *p_buf++;
128     if( p_key->version != 4 )
129         return VLC_EGENERIC;
130
131     /* warn when timestamp is > date ? */
132     memcpy( p_key->timestamp, p_buf, 4 ); p_buf += 4;
133
134     p_key->algo      = *p_buf++;
135     if( p_key->algo != PUBLIC_KEY_ALGO_DSA )
136         return VLC_EGENERIC;
137
138     int i_p_len = mpi_len( p_buf );
139     if( i_p_len > 128 )
140         return VLC_EGENERIC;
141     else
142     {
143         memcpy( p_key->p, p_buf, 2+i_p_len ); p_buf += 2+i_p_len;
144         if( i_p_len < 128 )
145             memmove( p_key->q, p_key->p + 2+i_p_len, 2+20 + 2+128 + 2+128 );
146     }
147
148     int i_q_len = mpi_len( p_buf );
149     if( i_q_len > 20 )
150         return VLC_EGENERIC;
151     else
152     {
153         memcpy( p_key->q, p_buf, 2+i_q_len );  p_buf += 2+i_q_len;
154         if( i_p_len < 20 )
155             memmove( p_key->g, p_key->q + 2+i_q_len, 2+128 + 2+128 );
156     }
157
158     int i_g_len = mpi_len( p_buf );
159     if( i_g_len > 128 )
160         return VLC_EGENERIC;
161     else
162     {
163         memcpy( p_key->g, p_buf, 2+i_g_len ); p_buf += 2+i_g_len;
164         if( i_g_len < 128 )
165             memmove( p_key->y, p_key->g + 2+i_g_len, 2+128 );
166     }
167
168     int i_y_len = mpi_len( p_buf );
169     if( i_y_len > 128 )
170         return VLC_EGENERIC;
171     else
172         memcpy( p_key->y, p_buf, 2+i_y_len );
173
174     return VLC_SUCCESS;
175 }
176
177 /*
178  * fill a signature_packet_v4_t from signature packet data
179  * verify that it was used with a DSA public key, using SHA-1 digest
180  */
181 static int parse_signature_v4_packet( signature_packet_v4_t *p_sig,
182                                       uint8_t *p_buf, size_t i_sig_len )
183 {
184     if( i_sig_len < 54 )
185         return VLC_EGENERIC;
186
187     p_sig->version = *p_buf++;
188     if( p_sig->version != 4 )
189         return VLC_EGENERIC;
190
191     p_sig->type = *p_buf++;
192     if( p_sig->type < GENERIC_KEY_SIGNATURE ||
193         p_sig->type > POSITIVE_KEY_SIGNATURE )
194         return VLC_EGENERIC;
195
196     p_sig->public_key_algo = *p_buf++;
197     if( p_sig->public_key_algo != PUBLIC_KEY_ALGO_DSA )
198         return VLC_EGENERIC;
199
200     p_sig->digest_algo = *p_buf++;
201     if( p_sig->digest_algo != DIGEST_ALGO_SHA1 )
202         return VLC_EGENERIC;
203
204     memcpy( p_sig->hashed_data_len, p_buf, 2 ); p_buf += 2;
205
206     size_t i_pos = 6;
207     size_t i_hashed_data_len = scalar_number( p_sig->hashed_data_len, 2 );
208     i_pos += i_hashed_data_len;
209     if( i_pos > i_sig_len - 48 ) /* r & s are 44 bytes in total,
210                               * + the unhashed data length (2 bytes)
211                               * + the hash verification (2 bytes) */
212         return VLC_EGENERIC;
213
214     p_sig->hashed_data = (uint8_t*) malloc( i_hashed_data_len );
215     if( !p_sig->hashed_data )
216         return VLC_ENOMEM;
217     memcpy( p_sig->hashed_data, p_buf, i_hashed_data_len );
218     p_buf += i_hashed_data_len;
219
220     memcpy( p_sig->unhashed_data_len, p_buf, 2 ); p_buf += 2;
221
222     size_t i_unhashed_data_len = scalar_number( p_sig->unhashed_data_len, 2 );
223     i_pos += 2 + i_unhashed_data_len;
224     if( i_pos != i_sig_len - 46 )
225     {
226         free( p_sig->hashed_data );
227         return VLC_EGENERIC;
228     }
229
230     p_sig->unhashed_data = (uint8_t*) malloc( i_unhashed_data_len );
231     if( !p_sig->unhashed_data )
232     {
233         free( p_sig->hashed_data );
234         return VLC_ENOMEM;
235     }
236     memcpy( p_sig->unhashed_data, p_buf, i_unhashed_data_len );
237     p_buf += i_unhashed_data_len;
238
239     memcpy( p_sig->hash_verification, p_buf, 2 ); p_buf += 2;
240
241     int i_r_len = mpi_len( p_buf );
242     if( i_r_len > 20 )
243     {
244         free( p_sig->hashed_data );
245         free( p_sig->unhashed_data );
246         return VLC_EGENERIC;
247     }
248     else
249     {
250         memcpy( p_sig->r, p_buf, 2 + i_r_len );
251         p_buf += 2 + i_r_len;
252     }
253
254     int i_s_len = mpi_len( p_buf );
255     if( i_s_len > 20 )
256     {
257         free( p_sig->hashed_data );
258         free( p_sig->unhashed_data );
259         return VLC_EGENERIC;
260     }
261     else
262     {
263         memcpy( p_sig->s, p_buf, 2 + i_s_len );
264         p_buf += 2 + i_s_len;
265     }
266
267     return VLC_SUCCESS;
268 }
269
270 /*
271  * crc_octets() was lamely copied from rfc 2440
272  * Copyright (C) The Internet Society (1998).  All Rights Reserved.
273  */
274 #define CRC24_INIT 0xB704CEL
275 #define CRC24_POLY 0x1864CFBL
276
277 static long crc_octets( uint8_t *octets, size_t len )
278 {
279     long crc = CRC24_INIT;
280     int i;
281     while (len--)
282     {
283         crc ^= (*octets++) << 16;
284         for (i = 0; i < 8; i++)
285         {
286             crc <<= 1;
287             if (crc & 0x1000000)
288                 crc ^= CRC24_POLY;
289         }
290     }
291     return crc & 0xFFFFFFL;
292 }
293
294 /*
295  * Transform an armored document in binary format
296  * Used on public keys and signatures
297  */
298 static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
299                         uint8_t *p_obuf, size_t i_obuf_len )
300 {
301     char *p_ipos = p_ibuf;
302     uint8_t *p_opos = p_obuf;
303     int i_end = 0;
304     int i_header_skipped = 0;
305
306     while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' )
307     {
308         if( *p_ipos == '\r' || *p_ipos == '\n' )
309         {
310             p_ipos++;
311             continue;
312         }
313
314         size_t i_line_len = strcspn( p_ipos, "\r\n" );
315         if( i_line_len == 0 )
316             continue;
317
318         if( !i_header_skipped )
319         {
320             if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) )
321                 i_header_skipped = 1;
322
323             p_ipos += i_line_len + 1;
324             continue;
325         }
326
327         if( !strncmp( p_ipos, "Version:", 8 ) )
328         {
329             p_ipos += i_line_len + 1;
330             continue;
331         }
332
333         if( p_ipos[i_line_len - 1] == '=' )
334         {
335             i_end = 1;
336             p_ipos[i_line_len - 1] = '\0';
337         }
338         else
339             p_ipos[i_line_len] = '\0';
340
341         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
342                         p_obuf - p_opos + i_obuf_len, p_ipos );
343         p_ipos += i_line_len + 1;
344     }
345
346     /* XXX: the CRC is OPTIONAL, really require it ? */
347     if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' )
348         return 0;
349
350     uint8_t p_crc[3];
351     if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 )
352         return 0;
353
354     long l_crc = crc_octets( p_obuf, p_opos - p_obuf );
355     long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2];
356
357     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
358 }
359
360 /*
361  * Download the signature associated to a document or a binary file.
362  * We're given the file's url, we just append ".asc" to it and download
363  */
364 static int download_signature(  vlc_object_t *p_this,
365                                 signature_packet_v3_t *p_sig,
366                                 const char *psz_url )
367 {
368     char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */
369     if( !psz_sig )
370         return VLC_ENOMEM;
371
372     strcpy( psz_sig, psz_url );
373     strcat( psz_sig, ".asc" );
374
375     stream_t *p_stream = stream_UrlNew( p_this, psz_sig );
376     free( psz_sig );
377
378     if( !p_stream )
379         return VLC_ENOMEM;
380
381     int64_t i_size = stream_Size( p_stream );
382     if( i_size <= 65 ) /* binary format signature */
383     {
384         msg_Dbg( p_this, "Downloading unarmored signature" );
385         int i_read = stream_Read( p_stream, p_sig, (int)i_size );
386         stream_Delete( p_stream );
387         if( i_read != i_size )
388         {
389             msg_Dbg( p_this, "Couldn't read full signature" );
390             return VLC_EGENERIC;
391         }
392         else
393             return VLC_SUCCESS;
394     }
395
396     msg_Dbg( p_this, "Downloading armored signature" );
397     char *p_buf = (char*)malloc( i_size );
398     if( !p_buf )
399     {
400         stream_Delete( p_stream );
401         return VLC_ENOMEM;
402     }
403
404     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
405
406     stream_Delete( p_stream );
407
408     if( i_read != i_size )
409     {
410         msg_Dbg( p_this, "Couldn't read full signature" );
411         free( p_buf );
412         return VLC_EGENERIC;
413     }
414
415     int i_bytes = pgp_unarmor( p_buf, i_size, (uint8_t*)p_sig, 65 );
416     free( p_buf );
417
418     if( i_bytes == 0 )
419     {
420         msg_Dbg( p_this, "Unarmoring failed" );
421         return VLC_EGENERIC;
422     }
423     else if( i_bytes > 65 )
424     {
425         msg_Dbg( p_this, "Signature is too big: %d bytes", i_bytes );
426         return VLC_EGENERIC;
427     }
428     else
429     {
430         int i_r_len = mpi_len( p_sig->r );
431         if( i_r_len > 20 )
432         {
433             msg_Dbg( p_this, "Invalid signature, r number too big: %d bytes",
434                                 i_r_len );
435             return VLC_EGENERIC;
436         }
437         else if( i_r_len < 20 )
438             /* move s to the right place if r is less than 20 bytes */
439             memmove( p_sig->s, p_sig->r + 2 + i_r_len, 20 + 2 );
440
441         return VLC_SUCCESS;
442     }
443 }
444
445 /*
446  * Verify an OpenPGP signature made on some SHA-1 hash, with some DSA public key
447  */
448 static int verify_signature( uint8_t *p_r, uint8_t *p_s,
449         public_key_packet_t *p_key, uint8_t *p_hash )
450 {
451     /* the data to be verified (a SHA-1 hash) */
452     const char *hash_sexp_s = "(data(flags raw)(value %m))";
453     /* the public key */
454     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
455     /* the signature */
456     const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))";
457
458     size_t erroff;
459     gcry_mpi_t p, q, g, y, r, s, hash;
460     p = q = g = y = r = s = hash = NULL;
461     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
462     key_sexp = hash_sexp = sig_sexp = NULL;
463
464     int i_p_len = mpi_len( p_key->p );
465     int i_q_len = mpi_len( p_key->q );
466     int i_g_len = mpi_len( p_key->g );
467     int i_y_len = mpi_len( p_key->y );
468     if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->p + 2, i_p_len, NULL ) ||
469         gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->q + 2, i_q_len, NULL ) ||
470         gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->g + 2, i_g_len, NULL ) ||
471         gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->y + 2, i_y_len, NULL ) ||
472         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
473         goto problem;
474
475     int i_r_len = mpi_len( p_r );
476     int i_s_len = mpi_len( p_s );
477     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
478         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
479         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
480         goto problem;
481
482     int i_hash_len = 20;
483     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
484         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
485         goto problem;
486
487     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
488         goto problem;
489
490     return VLC_SUCCESS;
491
492 problem:
493     if( p ) gcry_mpi_release( p );
494     if( q ) gcry_mpi_release( q );
495     if( g ) gcry_mpi_release( g );
496     if( y ) gcry_mpi_release( y );
497     if( r ) gcry_mpi_release( r );
498     if( s ) gcry_mpi_release( s );
499     if( hash ) gcry_mpi_release( hash );
500     if( key_sexp ) gcry_sexp_release( key_sexp );
501     if( sig_sexp ) gcry_sexp_release( sig_sexp );
502     if( hash_sexp ) gcry_sexp_release( hash_sexp );
503     return VLC_EGENERIC;
504 }
505
506 /*
507  * Return the long id (8 bytes) of the public key used to generate a signature
508  */
509 static uint8_t *get_issuer_from_signature_v4( signature_packet_v4_t *p_sig )
510 {
511     uint8_t *p = p_sig->unhashed_data;
512     uint8_t *max_pos = p + scalar_number( p_sig->unhashed_data_len, 2 );
513
514     while( p < max_pos )
515     {
516         int i_subpacket_len = *p < 192 ? *p++ :
517                 *p < 255 ? ((*p++ - 192) << 8) + *p++ + 192 :
518                 ((*++p) << 24) + (*++p << 16) + (*++p << 8) + *++p;
519
520         if( p >= max_pos - 1 )
521             return NULL;
522
523         if( *p == ISSUER_SUBPACKET )
524             return p+1;
525         else
526             p += i_subpacket_len;
527     }
528     return NULL;
529 }
530
531 /*
532  * fill a public_key_t with public key data, including:
533  *   * public key packet
534  *   * signature packet issued by key which long id is p_sig_issuer
535  *   * user id packet
536  */
537 static int parse_public_key( const uint8_t *p_key_data, size_t i_key_len, public_key_t *p_key, const uint8_t *p_sig_issuer )
538 {
539     uint8_t *pos = (uint8_t*) p_key_data;
540     uint8_t *max_pos = pos + i_key_len;
541
542     int i_status = 0;
543 #define PUBLIC_KEY_FOUND    0x01
544 #define USER_ID_FOUND       0x02
545 #define SIGNATURE_FOUND     0X04
546
547     uint8_t *p_key_unarmored = NULL;
548
549     signature_packet_v4_t sig;
550
551     p_key->psz_username = NULL;
552     p_key->sig.hashed_data = p_key->sig.unhashed_data = NULL;
553
554     if( !( *pos & 0x80 ) )
555     {   /* first byte is ASCII, unarmoring */
556         p_key_unarmored = (uint8_t*)malloc( i_key_len );
557         if( !p_key_unarmored )
558             return VLC_ENOMEM;
559         int i_len = pgp_unarmor( (char*)p_key_data, i_key_len,
560                                  p_key_unarmored, i_key_len );
561
562         if( i_len == 0 )
563             goto error;
564
565         pos = p_key_unarmored;
566         max_pos = pos + i_len;
567     }
568
569     while( pos < max_pos )
570     {
571         if( !(*pos & 0x80) || *pos & 0x40 )
572             goto error;
573
574         int i_type = packet_type( *pos );
575
576         int i_header_len = packet_header_len( *pos++ );
577         if( pos + i_header_len > max_pos )
578             goto error;
579
580         int i_packet_len = scalar_number( pos, i_header_len );
581         pos += i_header_len;
582
583         if( pos + i_packet_len > max_pos )
584             goto error;
585
586         switch( i_type )
587         {
588             uint8_t *p_issuer;
589
590             case PUBLIC_KEY_PACKET:
591                 i_status |= PUBLIC_KEY_FOUND;
592                 if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS )
593                     goto error;
594                 break;
595
596             case SIGNATURE_PACKET:
597                 if( !p_sig_issuer || i_status & SIGNATURE_FOUND ||
598                     parse_signature_v4_packet( &sig, pos, i_packet_len ) != VLC_SUCCESS )
599                     break;
600                 p_issuer = get_issuer_from_signature_v4( &sig );
601                 if( memcmp( p_issuer, p_sig_issuer, 8 ) == 0 )
602                 {
603                     memcpy( &p_key->sig, &sig, sizeof( signature_packet_v4_t ) );
604                     i_status |= SIGNATURE_FOUND;
605                 }
606                 else
607                 {
608                     free( sig.hashed_data );
609                     free( sig.unhashed_data );
610                 }
611                 break;
612
613             case USER_ID_PACKET:
614                 if( p_key->psz_username ) /* save only the first User ID */
615                     break;
616                 i_status |= USER_ID_FOUND;
617                 p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1);
618                 if( !p_key->psz_username )
619                     goto error;
620
621                 memcpy( p_key->psz_username, pos, i_packet_len );
622                 p_key->psz_username[i_packet_len] = '\0';
623                 break;
624
625             default:
626                 break;
627         }
628         pos += i_packet_len;
629     }
630     free( p_key_unarmored );
631
632     if( !( i_status & ( PUBLIC_KEY_FOUND + USER_ID_FOUND ) ) )
633         return VLC_EGENERIC;
634
635     if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) )
636         return VLC_EGENERIC;
637
638     return VLC_SUCCESS;
639
640 error:
641     free( p_key->sig.hashed_data );
642     free( p_key->sig.unhashed_data );
643     free( p_key->psz_username );
644     free( p_key_unarmored );
645     return VLC_EGENERIC;
646 }
647
648 /*
649  * return a sha1 hash of a file
650  */
651 static uint8_t *hash_sha1_from_file( const char *psz_file,
652                             signature_packet_v3_t *p_sig )
653 {
654     FILE *f = utf8_fopen( psz_file, "r" );
655     if( !f )
656         return NULL;
657
658     uint8_t buffer[4096];
659
660     gcry_md_hd_t hd;
661     if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
662     {
663         fclose( f );
664         return NULL;
665     }
666
667     size_t i_read;
668     while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 )
669         gcry_md_write( hd, buffer, i_read );
670
671     gcry_md_putc( hd, p_sig->type );
672     gcry_md_write( hd, &p_sig->timestamp, 4 );
673
674     fclose( f );
675     gcry_md_final( hd );
676
677     uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, GCRY_MD_SHA1);
678     uint8_t *p_hash = malloc( 20 );
679     if( p_hash )
680         memcpy( p_hash, p_tmp, 20 );
681     gcry_md_close( hd );
682     return p_hash;
683 }
684
685 /*
686  * download a public key (the last one) from videolan server, and parse it
687  */
688 static public_key_t *download_key( vlc_object_t *p_this, const uint8_t *p_longid, const uint8_t *p_signature_issuer )
689 {
690     char *psz_url;
691     if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc",
692                     p_longid[0], p_longid[1], p_longid[2], p_longid[3],
693                     p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 )
694         return NULL;
695
696     stream_t *p_stream = stream_UrlNew( p_this, psz_url );
697     free( psz_url );
698     if( !p_stream )
699         return NULL;
700
701     int64_t i_size = stream_Size( p_stream );
702     if( i_size < 0 )
703     {
704         stream_Delete( p_stream );
705         return NULL;
706     }
707
708     uint8_t *p_buf = (uint8_t*)malloc( i_size );
709     if( !p_buf )
710     {
711         stream_Delete( p_stream );
712         return NULL;
713     }
714
715     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
716     stream_Delete( p_stream );
717
718     if( i_read != (int)i_size )
719     {
720         msg_Dbg( p_this, "Couldn't read full GPG key" );
721         free( p_buf );
722         return NULL;
723     }
724
725     public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) );
726     if( !p_pkey )
727     {
728         free( p_buf );
729         return NULL;
730     }
731
732     int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer );
733     free( p_buf );
734
735     if( i_error != VLC_SUCCESS )
736     {
737         msg_Dbg( p_this, "Couldn't parse GPG key" );
738         free( p_pkey );
739         return NULL;
740     }
741
742     return p_pkey;
743 }
744
745 /*
746  * Generate a SHA-1 hash on a public key, to verify a signature made on that hash
747  * Note that we need the signature to compute the hash
748  */
749 static uint8_t *key_sign_hash( public_key_t *p_pkey )
750 {
751     gcry_error_t error = 0;
752     gcry_md_hd_t hd;
753
754     error = gcry_md_open( &hd, GCRY_MD_SHA1, 0 );
755     if( error )
756         return NULL;
757
758     gcry_md_putc( hd, 0x99 );
759
760     gcry_md_putc( hd, (418 >> 8) & 0xff );
761     gcry_md_putc( hd, 418 & 0xff );
762
763     gcry_md_write( hd, (uint8_t*)&p_pkey->key, 6 ); /* version,timestamp,algo */
764
765     int i_p_len = mpi_len( p_pkey->key.p );
766     gcry_md_write( hd, (uint8_t*)&p_pkey->key.p, 2 );
767     gcry_md_write( hd, (uint8_t*)&p_pkey->key.p + 2, i_p_len );
768
769     int i_g_len = mpi_len( p_pkey->key.g );
770     gcry_md_write( hd, (uint8_t*)&p_pkey->key.g, 2 );
771     gcry_md_write( hd, (uint8_t*)&p_pkey->key.g + 2, i_g_len );
772
773     int i_q_len = mpi_len( p_pkey->key.q );
774     gcry_md_write( hd, (uint8_t*)&p_pkey->key.q, 2 );
775     gcry_md_write( hd, (uint8_t*)&p_pkey->key.q + 2, i_q_len );
776
777     int i_y_len = mpi_len( p_pkey->key.y );
778     gcry_md_write( hd, (uint8_t*)&p_pkey->key.y, 2 );
779     gcry_md_write( hd, (uint8_t*)&p_pkey->key.y + 2, i_y_len );
780
781     gcry_md_putc( hd, 0xb4 );
782
783     int i_len = strlen((char*)p_pkey->psz_username);
784
785     gcry_md_putc( hd, (i_len << 24) & 0xff );
786     gcry_md_putc( hd, (i_len << 16) & 0xff );
787     gcry_md_putc( hd, (i_len << 8) & 0xff );
788     gcry_md_putc( hd, (i_len) & 0xff );
789
790     gcry_md_write( hd, p_pkey->psz_username, i_len );
791
792     size_t i_hashed_data_len = scalar_number( p_pkey->sig.hashed_data_len, 2 );
793
794     gcry_md_putc( hd, p_pkey->sig.version );
795     gcry_md_putc( hd, p_pkey->sig.type );
796     gcry_md_putc( hd, p_pkey->sig.public_key_algo );
797     gcry_md_putc( hd, p_pkey->sig.digest_algo );
798     gcry_md_write( hd, p_pkey->sig.hashed_data_len, 2 );
799     gcry_md_write( hd, p_pkey->sig.hashed_data, i_hashed_data_len );
800
801     gcry_md_putc( hd, 0x04 );
802     gcry_md_putc( hd, 0xff );
803
804     i_hashed_data_len += 6; /* hashed data + 6 bytes header */
805
806     gcry_md_putc( hd, (i_hashed_data_len << 24) & 0xff);
807     gcry_md_putc( hd, (i_hashed_data_len << 16) &0xff );
808     gcry_md_putc( hd, (i_hashed_data_len << 8) & 0xff );
809     gcry_md_putc( hd, (i_hashed_data_len) & 0xff );
810
811     gcry_md_final( hd );
812
813     uint8_t *p_tmp = gcry_md_read( hd, GCRY_MD_SHA1);
814
815     if( !p_tmp ||
816         p_tmp[0] != p_pkey->sig.hash_verification[0] ||
817         p_tmp[1] != p_pkey->sig.hash_verification[1] )
818     {
819         gcry_md_close( hd );
820         return NULL;
821     }
822
823     uint8_t *p_hash = malloc( 20 );
824     if( p_hash )
825         memcpy( p_hash, p_tmp, 20 );
826     gcry_md_close( hd );
827     return p_hash;
828 }
829
830
831 /*****************************************************************************
832  * Update_t functions
833  *****************************************************************************/
834
835 /**
836  * Create a new update VLC struct
837  *
838  * \param p_this the calling vlc_object
839  * \return pointer to new update_t or NULL
840  */
841 update_t *__update_New( vlc_object_t *p_this )
842 {
843     update_t *p_update;
844     assert( p_this );
845
846     p_update = (update_t *)malloc( sizeof( update_t ) );
847     if( !p_update ) return NULL;
848
849     vlc_mutex_init( &p_update->lock );
850
851     p_update->p_libvlc = p_this->p_libvlc;
852
853     p_update->release.psz_url = NULL;
854     p_update->release.psz_desc = NULL;
855
856     p_update->p_pkey = NULL;
857     vlc_gcrypt_init();
858
859     return p_update;
860 }
861
862 /**
863  * Delete an update_t struct
864  *
865  * \param p_update update_t* pointer
866  * \return nothing
867  */
868 void update_Delete( update_t *p_update )
869 {
870     assert( p_update );
871
872     vlc_mutex_destroy( &p_update->lock );
873
874     free( p_update->release.psz_url );
875     free( p_update->release.psz_desc );
876     free( p_update->p_pkey );
877
878     free( p_update );
879 }
880
881 /**
882  * Empty the release struct
883  *
884  * \param p_update update_t* pointer
885  * \return nothing
886  */
887 static void EmptyRelease( update_t *p_update )
888 {
889     p_update->release.i_major = 0;
890     p_update->release.i_minor = 0;
891     p_update->release.i_revision = 0;
892
893     FREENULL( p_update->release.psz_url );
894     FREENULL( p_update->release.psz_desc );
895 }
896
897 /**
898  * Get the update file and parse it
899  * p_update has to be locked when calling this function
900  *
901  * \param p_update pointer to update struct
902  * \return true if the update is valid and authenticated
903  */
904 static bool GetUpdateFile( update_t *p_update )
905 {
906     stream_t *p_stream = NULL;
907     int i_major = 0;
908     int i_minor = 0;
909     int i_revision = 0;
910     unsigned char extra;
911     char *psz_line = NULL;
912     char *psz_version_line = NULL;
913
914     p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL );
915     if( !p_stream )
916     {
917         msg_Err( p_update->p_libvlc, "Failed to open %s for reading",
918                  UPDATE_VLC_STATUS_URL );
919         goto error;
920     }
921
922     /* Try to read three lines */
923     if( !( psz_line = stream_ReadLine( p_stream ) ) )
924     {
925         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version",
926                  UPDATE_VLC_STATUS_URL );
927         goto error;
928     }
929
930     psz_version_line = psz_line;
931     /* first line : version number */
932     p_update->release.extra = 0;
933     switch( sscanf( psz_line, "%i.%i.%i%c", &i_major, &i_minor, &i_revision, &extra ) )
934     {
935         case 4:
936             p_update->release.extra = extra;
937         case 3:
938             p_update->release.i_major = i_major;
939             p_update->release.i_minor = i_minor;
940             p_update->release.i_revision = i_revision;
941             break;
942         default:
943             msg_Err( p_update->p_libvlc, "Update version false formated" );
944             goto error;
945     }
946
947     /* Second line : URL */
948     if( !( psz_line = stream_ReadLine( p_stream ) ) )
949     {
950         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing",
951                  UPDATE_VLC_STATUS_URL );
952         goto error;
953     }
954     p_update->release.psz_url = psz_line;
955
956
957     /* Third line : description */
958     if( !( psz_line = stream_ReadLine( p_stream ) ) )
959     {
960         msg_Err( p_update->p_libvlc, "Update file %s is corrupted : description missing",
961                  UPDATE_VLC_STATUS_URL );
962         goto error;
963     }
964     p_update->release.psz_desc = psz_line;
965
966     stream_Delete( p_stream );
967     p_stream = NULL;
968
969     /* Now that we know the status is valid, we must download its signature
970      * to authenticate it */
971     signature_packet_v3_t sign;
972     if( download_signature( VLC_OBJECT( p_update->p_libvlc ), &sign,
973             UPDATE_VLC_STATUS_URL ) != VLC_SUCCESS )
974     {
975         msg_Err( p_update->p_libvlc, "Couldn't download signature of status file" );
976         goto error;
977     }
978
979     if( sign.type != BINARY_SIGNATURE && sign.type != TEXT_SIGNATURE )
980     {
981         msg_Err( p_update->p_libvlc, "Invalid signature type" );
982         goto error;
983     }
984
985     p_update->p_pkey = (public_key_t*)malloc( sizeof( public_key_t ) );
986     if( !p_update->p_pkey )
987         goto error;
988
989     if( parse_public_key( videolan_public_key, sizeof( videolan_public_key ),
990                         p_update->p_pkey, NULL ) != VLC_SUCCESS )
991     {
992         msg_Err( p_update->p_libvlc, "Couldn't parse embedded public key, something went really wrong..." );
993         FREENULL( p_update->p_pkey );
994         goto error;
995     }
996
997     if( memcmp( sign.issuer_longid, videolan_public_key_longid , 8 ) != 0 )
998     {
999         msg_Dbg( p_update->p_libvlc, "Need to download the GPG key" );
1000         public_key_t *p_new_pkey = download_key(
1001                 VLC_OBJECT(p_update->p_libvlc),
1002                 sign.issuer_longid, videolan_public_key_longid );
1003         if( !p_new_pkey )
1004         {
1005             msg_Err( p_update->p_libvlc, "Couldn't download GPG key" );
1006             FREENULL( p_update->p_pkey );
1007             goto error;
1008         }
1009
1010         uint8_t *p_hash = key_sign_hash( p_new_pkey );
1011         if( !p_hash )
1012         {
1013             msg_Err( p_update->p_libvlc, "Failed to hash signature" );
1014             free( p_new_pkey );
1015             FREENULL( p_update->p_pkey );
1016             goto error;
1017         }
1018
1019         if( verify_signature( p_new_pkey->sig.r, p_new_pkey->sig.s,
1020                     &p_update->p_pkey->key, p_hash ) == VLC_SUCCESS )
1021         {
1022             free( p_hash );
1023             msg_Info( p_update->p_libvlc, "Key authenticated" );
1024             free( p_update->p_pkey );
1025             p_update->p_pkey = p_new_pkey;
1026         }
1027         else
1028         {
1029             free( p_hash );
1030             msg_Err( p_update->p_libvlc, "Key signature invalid !\n" );
1031             goto error;
1032         }
1033     }
1034
1035     gcry_md_hd_t hd;
1036     if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
1037         goto error_hd;
1038
1039     gcry_md_write( hd, psz_version_line, strlen( psz_version_line ) );
1040     FREENULL( psz_version_line );
1041     if( sign.type == TEXT_SIGNATURE )
1042         gcry_md_putc( hd, '\r' );
1043     gcry_md_putc( hd, '\n' );
1044     gcry_md_write( hd, p_update->release.psz_url,
1045                         strlen( p_update->release.psz_url ) );
1046     if( sign.type == TEXT_SIGNATURE )
1047         gcry_md_putc( hd, '\r' );
1048     gcry_md_putc( hd, '\n' );
1049     gcry_md_write( hd, p_update->release.psz_desc,
1050                         strlen( p_update->release.psz_desc ) );
1051     if( sign.type == TEXT_SIGNATURE )
1052         gcry_md_putc( hd, '\r' );
1053     gcry_md_putc( hd, '\n' );
1054
1055     gcry_md_putc( hd, sign.type );
1056     gcry_md_write( hd, &sign.timestamp, 4 );
1057
1058     gcry_md_final( hd );
1059
1060     uint8_t *p_hash = gcry_md_read( hd, GCRY_MD_SHA1 );
1061
1062     if( p_hash[0] != sign.hash_verification[0] ||
1063         p_hash[1] != sign.hash_verification[1] )
1064     {
1065         msg_Warn( p_update->p_libvlc, "Bad SHA1 hash for status file" );
1066         goto error_hd;
1067     }
1068
1069     if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
1070             != VLC_SUCCESS )
1071     {
1072         msg_Err( p_update->p_libvlc, "BAD SIGNATURE for status file" );
1073         goto error_hd;
1074     }
1075     else
1076     {
1077         msg_Info( p_update->p_libvlc, "Status file authenticated" );
1078         gcry_md_close( hd );
1079         return true;
1080     }
1081
1082 error_hd:
1083     gcry_md_close( hd );
1084 error:
1085     if( p_stream )
1086         stream_Delete( p_stream );
1087     free( psz_version_line );
1088     return false;
1089 }
1090
1091
1092 /**
1093  * Struct to launch the check in an other thread
1094  */
1095 typedef struct
1096 {
1097     VLC_COMMON_MEMBERS
1098     update_t *p_update;
1099     void (*pf_callback)( void *, bool );
1100     void *p_data;
1101 } update_check_thread_t;
1102
1103 void update_CheckReal( update_check_thread_t *p_uct );
1104
1105 /**
1106  * Check for updates
1107  *
1108  * \param p_update pointer to update struct
1109  * \param pf_callback pointer to a function to call when the update_check is finished
1110  * \param p_data pointer to some datas to give to the callback
1111  * \returns nothing
1112  */
1113 void update_Check( update_t *p_update, void (*pf_callback)( void*, bool ), void *p_data )
1114 {
1115     assert( p_update );
1116
1117     update_check_thread_t *p_uct = vlc_object_create( p_update->p_libvlc,
1118                                             sizeof( update_check_thread_t ) );
1119     if( !p_uct )
1120     {
1121         msg_Err( p_update->p_libvlc, "out of memory" );
1122         return;
1123     }
1124
1125     p_uct->p_update = p_update;
1126     p_uct->pf_callback = pf_callback;
1127     p_uct->p_data = p_data;
1128
1129     vlc_thread_create( p_uct, "check for update", update_CheckReal,
1130                        VLC_THREAD_PRIORITY_LOW, false );
1131 }
1132
1133 void update_CheckReal( update_check_thread_t *p_uct )
1134 {
1135     bool b_ret;
1136     vlc_mutex_lock( &p_uct->p_update->lock );
1137
1138     EmptyRelease( p_uct->p_update );
1139     b_ret = GetUpdateFile( p_uct->p_update );
1140     vlc_mutex_unlock( &p_uct->p_update->lock );
1141
1142     if( p_uct->pf_callback )
1143         (p_uct->pf_callback)( p_uct->p_data, b_ret );
1144
1145     vlc_object_release( p_uct );
1146 }
1147
1148 /**
1149  * Compare a given release's version number to the current VLC's one
1150  *
1151  * \param p_update structure
1152  * \return true if we have to upgrade to the given version to be up to date
1153  */
1154 bool update_NeedUpgrade( update_t *p_update )
1155 {
1156     assert( p_update );
1157
1158     return  p_update->release.i_major < *PACKAGE_VERSION_MAJOR - '0' ||
1159             p_update->release.i_minor < *PACKAGE_VERSION_MINOR - '0' ||
1160             p_update->release.i_revision < *PACKAGE_VERSION_REVISION ||
1161             p_update->release.extra < *PACKAGE_VERSION_EXTRA;
1162 }
1163
1164 /**
1165  * Convert a long int size in bytes to a string
1166  *
1167  * \param l_size the size in bytes
1168  * \return the size as a string
1169  */
1170 static char *size_str( long int l_size )
1171 {
1172     char *psz_tmp = NULL;
1173     int i_retval = 0;
1174     if( l_size >> 30 )
1175         i_retval = asprintf( &psz_tmp, "%.1f GB", (float)l_size/(1<<30) );
1176     else if( l_size >> 20 )
1177         i_retval = asprintf( &psz_tmp, "%.1f MB", (float)l_size/(1<<20) );
1178     else if( l_size >> 10 )
1179         i_retval = asprintf( &psz_tmp, "%.1f kB", (float)l_size/(1<<10) );
1180     else
1181         i_retval = asprintf( &psz_tmp, "%ld B", l_size );
1182
1183     return i_retval == -1 ? NULL : psz_tmp;
1184 }
1185
1186
1187 /**
1188  * Struct to launch the download in a thread
1189  */
1190 typedef struct
1191 {
1192     VLC_COMMON_MEMBERS
1193     update_t *p_update;
1194     char *psz_destdir;
1195 } update_download_thread_t;
1196
1197 void update_DownloadReal( update_download_thread_t *p_udt );
1198
1199 /**
1200  * Download the file given in the update_t
1201  *
1202  * \param p_update structure
1203  * \param dir to store the download file
1204  * \return nothing
1205  */
1206 void update_Download( update_t *p_update, char *psz_destdir )
1207 {
1208     assert( p_update );
1209
1210     update_download_thread_t *p_udt = vlc_object_create( p_update->p_libvlc,
1211                                         sizeof( update_download_thread_t ) );
1212     if( !p_udt )
1213     {
1214         msg_Err( p_update->p_libvlc, "out of memory" );
1215         return;
1216     }
1217
1218     p_udt->p_update = p_update;
1219     p_udt->psz_destdir = psz_destdir ? strdup( psz_destdir ) : NULL;
1220
1221     vlc_thread_create( p_udt, "download update", update_DownloadReal,
1222                        VLC_THREAD_PRIORITY_LOW, false );
1223 }
1224
1225 void update_DownloadReal( update_download_thread_t *p_udt )
1226 {
1227     int i_progress = 0;
1228     long int l_size;
1229     long int l_downloaded = 0;
1230     float f_progress;
1231     char *psz_status = NULL;
1232     char *psz_downloaded = NULL;
1233     char *psz_size = NULL;
1234     char *psz_destfile = NULL;
1235     char *psz_tmpdestfile = NULL;
1236
1237     FILE *p_file = NULL;
1238     stream_t *p_stream = NULL;
1239     void* p_buffer = NULL;
1240     int i_read;
1241
1242     update_t *p_update = p_udt->p_update;
1243     char *psz_destdir = p_udt->psz_destdir;
1244
1245     /* Open the stream */
1246     p_stream = stream_UrlNew( p_udt, p_update->release.psz_url );
1247     if( !p_stream )
1248     {
1249         msg_Err( p_udt, "Failed to open %s for reading", p_update->release.psz_url );
1250         goto end;
1251     }
1252
1253     /* Get the stream size */
1254     l_size = stream_Size( p_stream );
1255
1256     /* Get the file name and open it*/
1257     psz_tmpdestfile = strrchr( p_update->release.psz_url, '/' );
1258     if( !psz_tmpdestfile )
1259     {
1260         msg_Err( p_udt, "The URL %s is false formated", p_update->release.psz_url );
1261         goto end;
1262     }
1263     psz_tmpdestfile++;
1264     if( asprintf( &psz_destfile, "%s%s", psz_destdir, psz_tmpdestfile ) == -1 )
1265         goto end;
1266
1267     p_file = utf8_fopen( psz_destfile, "w" );
1268     if( !p_file )
1269     {
1270         msg_Err( p_udt, "Failed to open %s for writing", psz_destfile );
1271         goto end;
1272     }
1273
1274     /* Create a buffer and fill it with the downloaded file */
1275     p_buffer = (void *)malloc( 1 << 10 );
1276     if( !p_buffer )
1277         goto end;
1278
1279     psz_size = size_str( l_size );
1280     if( asprintf( &psz_status, "%s\nDownloading... O.O/%s %.1f%% done",
1281         p_update->release.psz_url, psz_size, 0.0 ) != -1 )
1282     {
1283         i_progress = intf_UserProgress( p_udt, "Downloading ...", psz_status, 0.0, 0 );
1284         free( psz_status );
1285     }
1286
1287     while( ( i_read = stream_Read( p_stream, p_buffer, 1 << 10 ) ) &&
1288                                    !intf_ProgressIsCancelled( p_udt, i_progress ) )
1289     {
1290         if( fwrite( p_buffer, i_read, 1, p_file ) < 1 )
1291         {
1292             msg_Err( p_udt, "Failed to write into %s", psz_destfile );
1293             break;
1294         }
1295
1296         l_downloaded += i_read;
1297         psz_downloaded = size_str( l_downloaded );
1298         f_progress = 100.0*(float)l_downloaded/(float)l_size;
1299
1300         if( asprintf( &psz_status, "%s\nDonwloading... %s/%s %.1f%% done",
1301                       p_update->release.psz_url, psz_downloaded, psz_size,
1302                       f_progress ) != -1 )
1303         {
1304             intf_ProgressUpdate( p_udt, i_progress, psz_status, f_progress, 0 );
1305             free( psz_status );
1306         }
1307         free( psz_downloaded );
1308     }
1309
1310     /* Finish the progress bar or delete the file if the user had canceled */
1311     fclose( p_file );
1312     p_file = NULL;
1313
1314     if( !intf_ProgressIsCancelled( p_udt, i_progress ) )
1315     {
1316         if( asprintf( &psz_status, "%s\nDone %s (100.0%%)",
1317             p_update->release.psz_url, psz_size ) != -1 )
1318         {
1319             intf_ProgressUpdate( p_udt, i_progress, psz_status, 100.0, 0 );
1320             free( psz_status );
1321         }
1322     }
1323     else
1324     {
1325         utf8_unlink( psz_destfile );
1326         goto end;
1327     }
1328
1329     signature_packet_v3_t sign;
1330     if( download_signature( VLC_OBJECT( p_udt ), &sign,
1331             p_update->release.psz_url ) != VLC_SUCCESS )
1332     {
1333         utf8_unlink( psz_destfile );
1334
1335         intf_UserFatal( p_udt, true, _("File can not be verified"),
1336             _("It was not possible to download a cryptographic signature for "
1337               "downloaded file \"%s\", and so VLC deleted it."),
1338             psz_destfile );
1339         msg_Err( p_udt, "Couldn't download signature of downloaded file" );
1340         goto end;
1341     }
1342
1343     if( memcmp( sign.issuer_longid, p_update->p_pkey->longid, 8 ) )
1344     {
1345         utf8_unlink( psz_destfile );
1346         msg_Err( p_udt, "Invalid signature issuer" );
1347         intf_UserFatal( p_udt, true, _("Invalid signature"),
1348             _("The cryptographic signature for downloaded file \"%s\" was "
1349               "invalid and couldn't be used to securely verify it, and so "
1350               "VLC deleted it."),
1351             psz_destfile );
1352         goto end;
1353     }
1354
1355     if( sign.type != BINARY_SIGNATURE )
1356     {
1357         utf8_unlink( psz_destfile );
1358         msg_Err( p_udt, "Invalid signature type" );
1359         intf_UserFatal( p_udt, true, _("Invalid signature"),
1360             _("The cryptographic signature for downloaded file \"%s\" was "
1361               "invalid and couldn't be used to securely verify it, and so "
1362               "VLC deleted it."),
1363             psz_destfile );
1364         goto end;
1365     }
1366
1367     uint8_t *p_hash = hash_sha1_from_file( psz_destfile, &sign );
1368     if( !p_hash )
1369     {
1370         msg_Err( p_udt, "Unable to hash %s", psz_destfile );
1371         utf8_unlink( psz_destfile );
1372         intf_UserFatal( p_udt, true, _("File not verifiable"),
1373             _("It was not possible to securely verify downloaded file \"%s\", "
1374               "and so VLC deleted it."),
1375             psz_destfile );
1376
1377         goto end;
1378     }
1379
1380     if( p_hash[0] != sign.hash_verification[0] ||
1381         p_hash[1] != sign.hash_verification[1] )
1382     {
1383         utf8_unlink( psz_destfile );
1384         intf_UserFatal( p_udt, true, _("File corrupted"),
1385             _("Downloaded file \"%s\" was corrupted, and so VLC deleted it."),
1386              psz_destfile );
1387         msg_Err( p_udt, "Bad SHA1 hash for %s", psz_destfile );
1388         free( p_hash );
1389         goto end;
1390     }
1391
1392     if( verify_signature( sign.r, sign.s, &p_update->p_pkey->key, p_hash )
1393             != VLC_SUCCESS )
1394     {
1395         utf8_unlink( psz_destfile );
1396         intf_UserFatal( p_udt, true, _("File corrupted"),
1397             _("Downloaded file \"%s\" was corrupted, and so VLC deleted it."),
1398              psz_destfile );
1399         msg_Err( p_udt, "BAD SIGNATURE for %s", psz_destfile );
1400         free( p_hash );
1401         goto end;
1402     }
1403
1404     msg_Info( p_udt, "%s authenticated", psz_destfile );
1405     free( p_hash );
1406
1407 end:
1408     if( p_stream )
1409         stream_Delete( p_stream );
1410     if( p_file )
1411         fclose( p_file );
1412     free( psz_destdir );
1413     free( psz_destfile );
1414     free( p_buffer );
1415     free( psz_size );
1416
1417     vlc_object_release( p_udt );
1418 }
1419
1420 #endif