root/src/misc/update.c

Revision d326548f0a9819e308261bf59e3b5103560f4898, 50.4 kB (checked in by Antoine Cellerier <dionoea@videolan.org>, 2 months ago)

Fix a few bugs in update pgp code.

1/ pgp v4 signature checks of status files with more than 506 bytes would fail
2/ pgp v4 signature checks would fail (code dupication sucks).

This code is quite a mess. We shouldn't need to implement all this lowlevel stuff. I'll remove most of it and use pgpme instead.

For the time being, this means that upcomming releases should use v3 signatures for the downloaded files and shouldn't use status files of more than 506 bytes (or maybe shouldn't use v4 signatures for status files either)

  • Property mode set to 100644
Line 
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
39 #include <vlc_common.h>
40 #include <vlc_update.h>
41
42 #ifdef UPDATE_CHECK
43
44 #include <assert.h>
45
46 #include <vlc_pgpkey.h>
47 #include <vlc_stream.h>
48 #include <vlc_strings.h>
49 #include <vlc_charset.h>
50 #include <vlc_interface.h>
51
52 #include <gcrypt.h>
53 #include <vlc_gcrypt.h>
54
55 #include "update.h"
56 #include "../libvlc.h"
57
58 /*****************************************************************************
59  * Misc defines
60  *****************************************************************************/
61
62 /*
63  * Here is the format of these "status files" :
64  * First line is the last version: "X.Y.Ze" where:
65  *      * X is the major number
66  *      * Y is the minor number
67  *      * Z is the revision number
68  *      * e is an OPTIONAL extra letter
69  *      * AKA "0.8.6d" or "0.9.0"
70  * Second line is an url of the binary for this last version
71  * Remaining text is a required description of the update
72  */
73
74 #if defined( UNDER_CE )
75 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-ce"
76 #elif defined( WIN32 )
77 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-win-x86"
78 #elif defined( __APPLE__ )
79 #   if defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ )
80 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-ppc"
81 #   else
82 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-mac-x86"
83 #   endif
84 #elif defined( SYS_BEOS )
85 #       define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status-beos-x86"
86 #else
87 #   define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
88 #endif
89
90
91 /*****************************************************************************
92  * Local Prototypes
93  *****************************************************************************/
94 static void EmptyRelease( update_t *p_update );
95 static bool GetUpdateFile( update_t *p_update );
96 static char * size_str( long int l_size );
97
98
99 /*****************************************************************************
100  * OpenPGP functions
101  *****************************************************************************/
102
103 #define packet_type( c ) ( ( c & 0x3c ) >> 2 )      /* 0x3C = 00111100 */
104 #define packet_header_len( c ) ( ( c & 0x03 ) + 1 ) /* number of bytes in a packet header */
105
106 static inline int scalar_number( uint8_t *p, int header_len )
107 {
108     assert( header_len == 1 || header_len == 2 || header_len == 4 );
109
110     if( header_len == 1 )
111         return( p[0] );
112     else if( header_len == 2 )
113         return( (p[0] << 8) + p[1] );
114     else if( header_len == 4 )
115         return( (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3] );
116
117     abort(); /* to shut up GCC warning */
118 }
119
120 /* number of data bytes in a MPI */
121 #define mpi_len( mpi ) ( ( scalar_number( mpi, 2 ) + 7 ) / 8 )
122
123 /*
124  * fill a public_key_packet_t structure from public key packet data
125  * verify that it is a version 4 public key packet, using DSA
126  */
127 static int parse_public_key_packet( public_key_packet_t *p_key, uint8_t *p_buf,
128                                     size_t i_packet_len )
129 {
130
131     if( i_packet_len > 418 || i_packet_len < 6 )
132         return VLC_EGENERIC;
133
134     size_t i_read = 0;
135
136     p_key->version   = *p_buf++; i_read++;
137     if( p_key->version != 4 )
138         return VLC_EGENERIC;
139
140     /* XXX: warn when timestamp is > date ? */
141     memcpy( p_key->timestamp, p_buf, 4 ); p_buf += 4; i_read += 4;
142
143     p_key->algo      = *p_buf++; i_read++;
144     if( p_key->algo != PUBLIC_KEY_ALGO_DSA )
145         return VLC_EGENERIC;
146
147     /* read p */
148     if( i_read + 2 > i_packet_len )
149         return VLC_EGENERIC;
150
151     int i_p_len = mpi_len( p_buf );
152
153     if( i_p_len > 128 || i_read + 2 + i_p_len > i_packet_len )
154         return VLC_EGENERIC;
155
156     memcpy( p_key->p, p_buf, 2+i_p_len );
157     p_buf += 2+i_p_len; i_read += 2+i_p_len;
158
159     /* read q */
160     if( i_read + 2 > i_packet_len )
161         return VLC_EGENERIC;
162
163     int i_q_len = mpi_len( p_buf );
164
165     if( i_q_len > 20 || i_read+2+i_q_len > i_packet_len )
166         return VLC_EGENERIC;
167
168     memcpy( p_key->q, p_buf, 2+i_q_len );
169     p_buf += 2+i_q_len; i_read += 2+i_q_len;
170
171     /* read g */
172     if( i_read + 2 > i_packet_len )
173         return VLC_EGENERIC;
174
175     int i_g_len = mpi_len( p_buf );
176
177     if( i_g_len > 128 || i_read+2+i_g_len > i_packet_len )
178         return VLC_EGENERIC;
179
180     memcpy( p_key->g, p_buf, 2+i_g_len );
181     p_buf += 2+i_g_len; i_read += 2+i_g_len;
182
183     /* read y */
184     if( i_read + 2 > i_packet_len )
185         return VLC_EGENERIC;
186
187     int i_y_len = mpi_len( p_buf );
188
189
190     if( i_y_len > 128 || i_read+2+i_y_len > i_packet_len )
191         return VLC_EGENERIC;
192
193     memcpy( p_key->y, p_buf, 2+i_y_len );
194     i_read += 2+i_y_len;
195
196     if( i_read != i_packet_len ) /* some extra data eh ? */
197         return VLC_EGENERIC;
198
199     return VLC_SUCCESS;
200 }
201
202 static size_t parse_signature_v3_packet( signature_packet_t *p_sig,
203                                       uint8_t *p_buf, size_t i_sig_len )
204 {
205     size_t i_read = 1; /* we already read the version byte */
206
207     if( i_sig_len < 19 ) /* signature is at least 19 bytes + the 2 MPIs */
208         return 0;
209
210     p_sig->specific.v3.hashed_data_len = *p_buf++; i_read++;
211     if( p_sig->specific.v3.hashed_data_len != 5 )
212         return 0;
213
214     p_sig->type = *p_buf++; i_read++;
215
216     memcpy( p_sig->specific.v3.timestamp, p_buf, 4 );
217     p_buf += 4; i_read += 4;
218
219     memcpy( p_sig->issuer_longid, p_buf, 8 );
220     p_buf += 8; i_read += 8;
221
222     p_sig->public_key_algo = *p_buf++; i_read++;
223
224     p_sig->digest_algo = *p_buf++; i_read++;
225
226     p_sig->hash_verification[0] = *p_buf++; i_read++;
227     p_sig->hash_verification[1] = *p_buf++; i_read++;
228
229     assert( i_read == 19 );
230
231     return i_read;
232 }
233
234 /*
235  * fill a signature_packet_v4_t from signature packet data
236  * verify that it was used with a DSA public key, using SHA-1 digest
237  */
238 static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
239                                       uint8_t *p_buf, size_t i_sig_len )
240 {
241     size_t i_read = 1; /* we already read the version byte */
242
243     if( i_sig_len < 10 ) /* signature is at least 10 bytes + the 2 MPIs */
244         return 0;
245
246     p_sig->type = *p_buf++; i_read++;
247
248     p_sig->public_key_algo = *p_buf++; i_read++;
249
250     p_sig->digest_algo = *p_buf++; i_read++;
251
252     memcpy( p_sig->specific.v4.hashed_data_len, p_buf, 2 );
253     p_buf += 2; i_read += 2;
254
255     size_t i_hashed_data_len =
256         scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
257     i_read += i_hashed_data_len;
258     if( i_read + 4 > i_sig_len )
259         return 0;
260
261     p_sig->specific.v4.hashed_data = (uint8_t*) malloc( i_hashed_data_len );
262     if( !p_sig->specific.v4.hashed_data )
263         return 0;
264     memcpy( p_sig->specific.v4.hashed_data, p_buf, i_hashed_data_len );
265     p_buf += i_hashed_data_len;
266
267     memcpy( p_sig->specific.v4.unhashed_data_len, p_buf, 2 );
268     p_buf += 2; i_read += 2;
269
270     size_t i_unhashed_data_len =
271         scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
272     i_read += i_unhashed_data_len;
273     if( i_read + 2 > i_sig_len )
274         return 0;
275
276     p_sig->specific.v4.unhashed_data = (uint8_t*) malloc( i_unhashed_data_len );
277     if( !p_sig->specific.v4.unhashed_data )
278         return 0;
279
280     memcpy( p_sig->specific.v4.unhashed_data, p_buf, i_unhashed_data_len );
281     p_buf += i_unhashed_data_len;
282
283     memcpy( p_sig->hash_verification, p_buf, 2 );
284     p_buf += 2; i_read += 2;
285
286     uint8_t *p, *max_pos;
287     p = p_sig->specific.v4.unhashed_data;
288     max_pos = p + scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
289
290     for( ;; )
291     {
292         if( p > max_pos )
293             return 0;
294
295         size_t i_subpacket_len;
296         if( *p < 192 )
297         {
298             if( p + 1 > max_pos )
299                 return 0;
300             i_subpacket_len = *p++;
301         }
302         else if( *p < 255 )
303         {
304             if( p + 2 > max_pos )
305                 return 0;
306             i_subpacket_len = (*p++ - 192) << 8;
307             i_subpacket_len += *p++ + 192;
308         }
309         else
310         {
311             if( p + 4 > max_pos )
312                 return 0;
313             i_subpacket_len = *++p << 24;
314             i_subpacket_len += *++p << 16;
315             i_subpacket_len += *++p << 8;
316             i_subpacket_len += *++p;
317         }
318
319         if( *p == ISSUER_SUBPACKET )
320         {
321             if( p + 9 > max_pos )
322                 return 0;
323
324             memcpy( &p_sig->issuer_longid, p+1, 8 );
325
326             return i_read;
327         }
328
329         p += i_subpacket_len;
330     }
331 }
332
333 static int parse_signature_packet( signature_packet_t *p_sig,
334                                    uint8_t *p_buf, size_t i_sig_len )
335 {
336     if( !i_sig_len ) /* 1st sanity check, we need at least the version */
337         return VLC_EGENERIC;
338
339     p_sig->version = *p_buf++;
340
341     size_t i_read;
342     switch( p_sig->version )
343     {
344         case 3:
345             i_read = parse_signature_v3_packet( p_sig, p_buf, i_sig_len );
346             break;
347         case 4:
348             p_sig->specific.v4.hashed_data = NULL;
349             p_sig->specific.v4.unhashed_data = NULL;
350             i_read = parse_signature_v4_packet( p_sig, p_buf, i_sig_len );
351             break;
352         default:
353             return VLC_EGENERIC;
354     }
355
356     if( i_read == 0 ) /* signature packet parsing has failed */
357         goto error;
358
359     if( p_sig->public_key_algo != PUBLIC_KEY_ALGO_DSA )
360         goto error;
361
362     if( p_sig->digest_algo != DIGEST_ALGO_SHA1 )
363         goto error;
364
365     switch( p_sig->type )
366     {
367         case BINARY_SIGNATURE:
368         case TEXT_SIGNATURE:
369         case GENERIC_KEY_SIGNATURE:
370         case PERSONA_KEY_SIGNATURE:
371         case CASUAL_KEY_SIGNATURE:
372         case POSITIVE_KEY_SIGNATURE:
373             break;
374         default:
375             goto error;
376     }
377
378     p_buf--; /* rewind to the version byte */
379     p_buf += i_read;
380
381     if( i_read + 2 > i_sig_len )
382         goto error;
383
384     size_t i_r_len = mpi_len( p_buf ); i_read += 2;
385     if( i_read + i_r_len > i_sig_len || i_r_len > 20 )
386         goto error;
387
388     memcpy( p_sig->r, p_buf, 2 + i_r_len );
389     p_buf += 2 + i_r_len;
390     i_read += i_r_len;
391
392     if( i_read + 2 > i_sig_len )
393         goto error;
394
395     size_t i_s_len = mpi_len( p_buf ); i_read += 2;
396     if( i_read + i_s_len > i_sig_len || i_s_len > 20 )
397         goto error;
398
399     memcpy( p_sig->s, p_buf, 2 + i_s_len );
400     p_buf += 2 + i_s_len;
401     i_read += i_s_len;
402
403     assert( i_read == i_sig_len );
404     if( i_read < i_sig_len ) /* some extra data, hm ? */
405         goto error;
406
407     return VLC_SUCCESS;
408
409 error:
410
411     if( p_sig->version == 4 )
412     {
413         free( p_sig->specific.v4.hashed_data );
414         free( p_sig->specific.v4.unhashed_data );
415     }
416
417     return VLC_EGENERIC;
418 }
419
420 /*
421  * crc_octets() was lamely copied from rfc 2440
422  * Copyright (C) The Internet Society (1998).  All Rights Reserved.
423  */
424 #define CRC24_INIT 0xB704CEL
425 #define CRC24_POLY 0x1864CFBL
426
427 static long crc_octets( uint8_t *octets, size_t len )
428 {
429     long crc = CRC24_INIT;
430     int i;
431     while (len--)
432     {
433         crc ^= (*octets++) << 16;
434         for (i = 0; i < 8; i++)
435         {
436             crc <<= 1;
437             if (crc & 0x1000000)
438                 crc ^= CRC24_POLY;
439         }
440     }
441     return crc & 0xFFFFFFL;
442 }
443
444 /*
445  * Transform an armored document in binary format
446  * Used on public keys and signatures
447  */
448 static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
449                         uint8_t *p_obuf, size_t i_obuf_len )
450 {
451     char *p_ipos = p_ibuf;
452     uint8_t *p_opos = p_obuf;
453     int i_end = 0;
454     int i_header_skipped = 0;
455
456     while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' )
457     {
458         if( *p_ipos == '\r' || *p_ipos == '\n' )
459         {
460             p_ipos++;
461             continue;
462         }
463
464         size_t i_line_len = strcspn( p_ipos, "\r\n" );
465         if( i_line_len == 0 )
466             continue;
467
468         if( !i_header_skipped )
469         {
470             if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) )
471                 i_header_skipped = 1;
472
473             p_ipos += i_line_len + 1;
474             continue;
475         }
476
477         if( !strncmp( p_ipos, "Version:", 8 ) )
478         {
479             p_ipos += i_line_len + 1;
480             continue;
481         }
482
483         if( p_ipos[i_line_len - 1] == '=' )
484         {
485             i_end = 1;
486             p_ipos[i_line_len - 1] = '\0';
487         }
488         else
489             p_ipos[i_line_len] = '\0';
490
491         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
492                         p_obuf - p_opos + i_obuf_len, p_ipos );
493         p_ipos += i_line_len + 1;
494     }
495
496     /* XXX: the CRC is OPTIONAL, really require it ? */
497     if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' )
498         return 0;
499
500     uint8_t p_crc[3];
501     if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 )
502         return 0;
503
504     long l_crc = crc_octets( p_obuf, p_opos - p_obuf );
505     long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2];
506
507     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
508 }
509
510 /*
511  * Download the signature associated to a document or a binary file.
512  * We're given the file's url, we just append ".asc" to it and download
513  */
514 static int download_signature(  vlc_object_t *p_this,
515                                 signature_packet_t *p_sig,
516                                 const char *psz_url )
517 {
518     char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */
519     if( !psz_sig )
520         return VLC_ENOMEM;
521
522     strcpy( psz_sig, psz_url );
523     strcat( psz_sig, ".asc" );
524
525     stream_t *p_stream = stream_UrlNew( p_this, psz_sig );
526     free( psz_sig );
527
528     if( !p_stream )
529         return VLC_ENOMEM;
530
531     int64_t i_size = stream_Size( p_stream );
532
533     msg_Dbg( p_this, "Downloading signature (%"PRId64" bytes)", i_size );
534     uint8_t *p_buf = (uint8_t*)malloc( i_size );
535     if( !p_buf )
536     {
537         stream_Delete( p_stream );
538         return VLC_ENOMEM;
539     }
540
541     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
542
543     stream_Delete( p_stream );
544
545     if( i_read != (int)i_size )
546     {
547         msg_Dbg( p_this,
548             "Couldn't download full signature (only %d bytes)", i_read );
549         free( p_buf );
550         return VLC_EGENERIC;
551     }
552
553     if( (uint8_t)*p_buf < 0x80 ) /* ASCII */
554     {
555         msg_Dbg( p_this, "Unarmoring signature" );
556
557         uint8_t* p_unarmored = (uint8_t*) malloc( ( i_size * 3 ) / 4 + 1 );
558         if( !p_unarmored )
559         {
560             free( p_buf );
561             return VLC_EGENERIC;
562         }
563
564         int i_bytes = pgp_unarmor( (char*)p_buf, i_size, p_unarmored, i_size );
565         free( p_buf );
566
567         p_buf = p_unarmored;
568         i_size = i_bytes;
569
570         if( i_bytes < 2 )
571         {
572             free( p_buf );
573             msg_Dbg( p_this, "Unarmoring failed : corrupted signature ?" );
574             return VLC_EGENERIC;
575         }
576     }
577
578     if( packet_type( *p_buf ) != SIGNATURE_PACKET )
579     {
580         free( p_buf );
581         msg_Dbg( p_this, "Not a signature: %d", *p_buf );
582         return VLC_EGENERIC;
583     }
584
585     size_t i_header_len = packet_header_len( *p_buf );
586     if( ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ||
587         i_header_len + 1 > (size_t)i_size )
588     {
589         free( p_buf );
590         msg_Dbg( p_this, "Invalid signature packet header" );
591         return VLC_EGENERIC;
592     }
593
594     size_t i_len = scalar_number( p_buf+1, i_header_len );
595     if( i_len + i_header_len + 1 != (size_t)i_size )
596     {
597         free( p_buf );
598         msg_Dbg( p_this, "Invalid signature packet" );
599         return VLC_EGENERIC;
600     }
601
602     int i_ret = parse_signature_packet( p_sig, p_buf+1+i_header_len, i_len );
603     free( p_buf );
604     if( i_ret != VLC_SUCCESS )
605     {
606         msg_Dbg( p_this, "Couldn't parse signature" );
607         return i_ret;
608     }
609
610     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
611     {
612         msg_Dbg( p_this, "Invalid signature type: %d", p_sig->type );
613         if( p_sig->version == 4 )
614         {
615             free( p_sig->specific.v4.hashed_data );
616             free( p_sig->specific.v4.unhashed_data );
617         }
618         return VLC_EGENERIC;
619     }
620
621     return VLC_SUCCESS;
622 }
623
624 /*
625  * Verify an OpenPGP signature made on some SHA-1 hash, with some DSA public key
626  */
627 static int verify_signature( uint8_t *p_r, uint8_t *p_s,
628         public_key_packet_t *p_key, uint8_t *p_hash )
629 {
630     /* the data to be verified (a SHA-1 hash) */
631     const char *hash_sexp_s = "(data(flags raw)(value %m))";
632     /* the public key */
633     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
634     /* the signature */
635     const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))";
636
637     size_t erroff;
638     gcry_mpi_t p, q, g, y, r, s, hash;
639     p = q = g = y = r = s = hash = NULL;
640     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
641     key_sexp = hash_sexp = sig_sexp = NULL;
642
643     int i_p_len = mpi_len( p_key->p );
644     int i_q_len = mpi_len( p_key->q );
645     int i_g_len = mpi_len( p_key->g );
646     int i_y_len = mpi_len( p_key->y );
647     if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->p + 2, i_p_len, NULL ) ||
648         gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->q + 2, i_q_len, NULL ) ||
649         gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->g + 2, i_g_len, NULL ) ||
650         gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->y + 2, i_y_len, NULL ) ||
651         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
652         goto problem;
653
654     int i_r_len = mpi_len( p_r );
655     int i_s_len = mpi_len( p_s );
656     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
657         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
658         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
659         goto problem;
660
661     int i_hash_len = 20;
662     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
663         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
664         goto problem;
665
666     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
667         goto problem;
668
669     return VLC_SUCCESS;
670
671 problem:
672     if( p ) gcry_mpi_release( p );
673     if( q ) gcry_mpi_release( q );
674     if( g ) gcry_mpi_release( g );
675     if( y ) gcry_mpi_release( y );
676     if( r ) gcry_mpi_release( r );
677     if( s ) gcry_mpi_release( s );
678     if( hash ) gcry_mpi_release( hash );
679     if( key_sexp ) gcry_sexp_release( key_sexp );
680     if( sig_sexp ) gcry_sexp_release( sig_sexp );
681     if( hash_sexp ) gcry_sexp_release( hash_sexp );
682     return VLC_EGENERIC;
683 }
684
685 /*
686  * fill a public_key_t with public key data, including:
687  *   * public key packet
688  *   * signature packet issued by key which long id is p_sig_issuer
689  *   * user id packet
690  */
691 static int parse_public_key( const uint8_t *p_key_data, size_t i_key_len,
692                              public_key_t *p_key, const uint8_t *p_sig_issuer )
693 {
694     uint8_t *pos = (uint8_t*) p_key_data;
695     uint8_t *max_pos = pos + i_key_len;
696
697     int i_status = 0;
698 #define PUBLIC_KEY_FOUND    0x01
699 #define USER_ID_FOUND       0x02
700 #define SIGNATURE_FOUND     0X04
701
702     uint8_t *p_key_unarmored = NULL;
703
704     p_key->psz_username = NULL;
705     p_key->sig.specific.v4.hashed_data = NULL;
706     p_key->sig.specific.v4.unhashed_data = NULL;
707
708     if( !( *pos & 0x80 ) )
709     {   /* first byte is ASCII, unarmoring */
710         p_key_unarmored = (uint8_t*)malloc( i_key_len );
711         if( !p_key_unarmored )
712             return VLC_ENOMEM;
713         int i_len = pgp_unarmor( (char*)p_key_data, i_key_len,
714                                  p_key_unarmored, i_key_len );
715
716         if( i_len == 0 )
717             goto error;
718
719         pos = p_key_unarmored;
720         max_pos = pos + i_len;
721     }
722
723     while( pos < max_pos )
724     {
725         if( !(*pos & 0x80) || *pos & 0x40 )
726             goto error;
727
728         int i_type = packet_type( *pos );
729
730         int i_header_len = packet_header_len( *pos++ );
731         if( pos + i_header_len > max_pos ||
732             ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) )
733             goto error;
734
735         int i_packet_len = scalar_number( pos, i_header_len );
736         pos += i_header_len;
737
738         if( pos + i_packet_len > max_pos )
739             goto error;
740
741         switch( i_type )
742         {
743             case PUBLIC_KEY_PACKET:
744                 i_status |= PUBLIC_KEY_FOUND;
745                 if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS )
746                     goto error;
747                 break;
748
749             case SIGNATURE_PACKET: /* we accept only v4 signatures here */
750                 if( i_status & SIGNATURE_FOUND || !p_sig_issuer )
751                     break;
752                 int i_ret = parse_signature_packet( &p_key->sig, pos,
753                                                     i_packet_len );
754                 if( i_ret == VLC_SUCCESS )
755                 {
756                     if( p_key->sig.version != 4 )
757                         break;
758                     if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) )
759                     {
760                         free( p_key->sig.specific.v4.hashed_data );
761                         free( p_key->sig.specific.v4.unhashed_data );
762                         p_key->sig.specific.v4.hashed_data = NULL;
763                         p_key->sig.specific.v4.unhashed_data = NULL;
764                         break;
765                     }
766                     i_status |= SIGNATURE_FOUND;
767                 }
768                 break;
769
770             case USER_ID_PACKET:
771                 if( p_key->psz_username ) /* save only the first User ID */
772                     break;
773                 i_status |= USER_ID_FOUND;
774                 p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1);
775                 if( !p_key->psz_username )
776                     goto error;
777
778                 memcpy( p_key->psz_username, pos, i_packet_len );
779                 p_key->psz_username[i_packet_len] = '\0';
780                 break;
781
782             default:
783                 break;
784         }
785         pos += i_packet_len;
786     }
787     free( p_key_unarmored );
788
789     if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) )
790         return VLC_EGENERIC;
791
792     if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) )
793         return VLC_EGENERIC;
794
795     return VLC_SUCCESS;
796
797 error:
798     if( p_key->sig.version == 4 )
799     {
800         free( p_key->sig.specific.v4.hashed_data );
801         free( p_key->sig.specific.v4.unhashed_data );
802     }
803     free( p_key->psz_username );
804     free( p_key_unarmored );
805     return VLC_EGENERIC;
806 }
807
808 /*
809  * return a sha1 hash of a file
810  */
811 static uint8_t *hash_sha1_from_file( const char *psz_file,
812                             signature_packet_t *p_sig )
813 {
814     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
815         return NULL;
816
817     FILE *f = utf8_fopen( psz_file, "r" );
818     if( !f )
819         return NULL;
820
821     uint8_t buffer[4096];
822
823     gcry_md_hd_t hd;
824     if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
825     {
826         fclose( f );
827         return NULL;
828     }
829
830     size_t i_read;
831     while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 )
832         gcry_md_write( hd, buffer, i_read );
833
834     if( p_sig->version == 3 )
835     {
836         gcry_md_putc( hd, p_sig->type );
837         gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 );
838     }
839     else if( p_sig->version == 4 )
840     {
841         gcry_md_putc( hd, p_sig->version );
842         gcry_md_putc( hd, p_sig->type );
843         gcry_md_putc( hd, p_sig->public_key_algo );
844         gcry_md_putc( hd, p_sig->digest_algo );
845         gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 );
846         size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
847         gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len );
848
849         gcry_md_putc( hd, 0x04 );
850         gcry_md_putc( hd, 0xFF );
851
852         i_len += 6; /* hashed data + 6 bytes header */
853
854         gcry_md_putc( hd, (i_len >> 24) & 0xff );
855         gcry_md_putc( hd, (i_len >> 16) & 0xff );
856         gcry_md_putc( hd, (i_len >> 8) & 0xff );
857         gcry_md_putc( hd, (i_len) & 0xff );
858     }
859     else
860     {   /* RFC 4880 only tells about versions 3 and 4 */
861         gcry_md_close( hd );
862         return NULL;
863     }
864
865     fclose( f );
866     gcry_md_final( hd );
867
868     uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, GCRY_MD_SHA1);
869     uint8_t *p_hash = malloc( 20 );
870     if( p_hash )
871         memcpy( p_hash, p_tmp, 20 );
872     gcry_md_close( hd );
873     return p_hash;
874 }
875
876 /*
877  * download a public key (the last one) from videolan server, and parse it
878  */
879 static public_key_t *download_key( vlc_object_t *p_this,
880                     const uint8_t *p_longid, const uint8_t *p_signature_issuer )
881 {
882     char *psz_url;
883     if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc",
884                     p_longid[0], p_longid[1], p_longid[2], p_longid[3],
885                     p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 )
886         return NULL;
887
888     stream_t *p_stream = stream_UrlNew( p_this, psz_url );
889     free( psz_url );
890     if( !p_stream )
891         return NULL;
892
893     int64_t i_size = stream_Size( p_stream );
894     if( i_size < 0 )
895     {
896         stream_Delete( p_stream );
897         return NULL;
898     }
899
900     uint8_t *p_buf = (uint8_t*)malloc( i_size );
901     if( !p_buf )
902     {
903         stream_Delete( p_stream );
904         return NULL;
905     }
906
907     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
908     stream_Delete( p_stream );
909
910     if( i_read != (int)i_size )
911     {
912         msg_Dbg( p_this, "Couldn't read full GPG key" );
913         free( p_buf );
914         return NULL;
915     }
916
917     public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) );
918     if( !p_pkey )
919     {
920         free( p_buf );
921         return NULL;
922     }
923
924     memcpy( p_pkey->longid, p_longid, 8 );
925
926     int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer );
927     free( p_buf );
928
929     if( i_error != VLC_SUCCESS )
930     {
931         msg_Dbg( p_this, "Couldn't parse GPG key" );
932         free( p_pkey );
933         return NULL;
934     }
935
936     return p_pkey;
937 }
938
939 /*
940  * Generate a SHA1 hash on a public key, to verify a signature made on that hash
941  * Note that we need the signature (v4) to compute the hash
942  */
943 static uint8_t *key_sign_hash( public_key_t *p_pkey )
944 {
945     if( p_pkey->sig.version != 4 )
946         return NULL;
947
948     if( p_pkey->sig.type < GENERIC_KEY_SIGNATURE ||
949         p_pkey->sig.type > POSITIVE_KEY_SIGNATURE )
950         return NULL;
951
952     gcry_error_t error = 0;
953     gcry_md_hd_t hd;
954
955     error = gcry_md_open( &hd, GCRY_MD_SHA1, 0 );
956     if( error )
957         return NULL;
958
959     gcry_md_putc( hd, 0x99 );
960
961     size_t i_p_len = mpi_len( p_pkey->key.p );
962     size_t i_g_len = mpi_len( p_pkey->key.g );
963     size_t i_q_len = mpi_len( p_pkey->key.q );
964     size_t i_y_len = mpi_l