update: use U32_AT
[vlc.git] / src / misc / update_crypto.c
1 /*****************************************************************************
2  * update_crypto.c: OpenPGP related functions used for updating
3  *****************************************************************************
4  * Copyright © 2008-2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Rafaël Carré <funman@videolanorg>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either release 2 of the License, or
12  * (at your option) any later release.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /**
25  *   \file
26  *   This file contains functions related to OpenPGP in VLC update management
27  */
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #ifdef UPDATE_CHECK
38
39 #include <gcrypt.h>
40 #include <assert.h>
41
42 #include "vlc_common.h"
43 #include <vlc_stream.h>
44 #include <vlc_strings.h>
45 #include <vlc_fs.h>
46
47 #include "update.h"
48
49
50 /*****************************************************************************
51  * OpenPGP functions
52  *****************************************************************************/
53
54 #define packet_type( c ) ( ( c & 0x3c ) >> 2 )      /* 0x3C = 00111100 */
55 #define packet_header_len( c ) ( ( c & 0x03 ) + 1 ) /* number of bytes in a packet header */
56
57
58 static inline int scalar_number( const uint8_t *p, int header_len )
59 {
60     assert( header_len == 1 || header_len == 2 || header_len == 4 );
61
62     if( header_len == 1 )
63         return( p[0] );
64     else if( header_len == 2 )
65         return( (p[0] << 8) + p[1] );
66     else if( header_len == 4 )
67         return( (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3] );
68     else
69         abort();
70 }
71
72
73 /* number of data bytes in a MPI */
74 static int mpi_len(const uint8_t *mpi)
75 {
76     return (scalar_number(mpi, 2) + 7) / 8;
77 }
78
79 static size_t read_mpi(uint8_t *dst, const uint8_t *buf, size_t buflen, size_t bits)
80 {
81     if (buflen < 2)
82         return 0;
83
84     size_t n = mpi_len(buf);
85
86     if (n * 8 > bits)
87         return 0;
88
89     n += 2;
90
91     if (buflen < n)
92         return 0;
93
94     memcpy(dst, buf, n);
95     return n;
96 }
97
98 #define READ_MPI(d, bits) do { \
99     size_t n = read_mpi(d, p_buf, i_packet_len - i_read, bits); \
100     if (!n) goto error; \
101     p_buf += n; \
102     i_read += n; \
103 } while(0)
104
105 /*
106  * fill a public_key_packet_t structure from public key packet data
107  * verify that it is a version 4 public key packet, using DSA or RSA
108  */
109 static int parse_public_key_packet( public_key_packet_t *p_key,
110                                     const uint8_t *p_buf, size_t i_packet_len )
111 {
112     if( i_packet_len < 6 )
113         return VLC_EGENERIC;
114
115     size_t i_read = 0;
116
117     p_key->version   = *p_buf++; i_read++;
118     if( p_key->version != 4 )
119         return VLC_EGENERIC;
120
121     /* XXX: warn when timestamp is > date ? */
122     memcpy( p_key->timestamp, p_buf, 4 ); p_buf += 4; i_read += 4;
123
124     p_key->algo      = *p_buf++; i_read++;
125     if( p_key->algo == GCRY_PK_DSA ) {
126         READ_MPI(p_key->sig.dsa.p, 3072);
127         READ_MPI(p_key->sig.dsa.q, 256);
128         READ_MPI(p_key->sig.dsa.g, 3072);
129         READ_MPI(p_key->sig.dsa.y, 3072);
130     } else if ( p_key->algo == GCRY_PK_RSA ) {
131         READ_MPI(p_key->sig.rsa.n, 4096);
132         READ_MPI(p_key->sig.rsa.e, 4096);
133     } else
134         return VLC_EGENERIC;
135
136     if( i_read == i_packet_len )
137         return VLC_SUCCESS;
138
139     /* some extra data eh ? */
140
141 error:
142     return VLC_EGENERIC;
143 }
144
145
146 static size_t parse_signature_v3_packet( signature_packet_t *p_sig,
147                                       const uint8_t *p_buf, size_t i_sig_len )
148 {
149     size_t i_read = 1; /* we already read the version byte */
150
151     if( i_sig_len < 19 ) /* signature is at least 19 bytes + the 2 MPIs */
152         return 0;
153
154     p_sig->specific.v3.hashed_data_len = *p_buf++; i_read++;
155     if( p_sig->specific.v3.hashed_data_len != 5 )
156         return 0;
157
158     p_sig->type = *p_buf++; i_read++;
159
160     memcpy( p_sig->specific.v3.timestamp, p_buf, 4 );
161     p_buf += 4; i_read += 4;
162
163     memcpy( p_sig->issuer_longid, p_buf, 8 );
164     p_buf += 8; i_read += 8;
165
166     p_sig->public_key_algo = *p_buf++; i_read++;
167
168     p_sig->digest_algo = *p_buf++; i_read++;
169
170     p_sig->hash_verification[0] = *p_buf++; i_read++;
171     p_sig->hash_verification[1] = *p_buf++; i_read++;
172
173     assert( i_read == 19 );
174
175     return i_read;
176 }
177
178
179 /*
180  * fill a signature_packet_v4_t from signature packet data
181  * verify that it was used with a DSA or RSA public key
182  */
183 static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
184                                       const uint8_t *p_buf, size_t i_sig_len )
185 {
186     size_t i_read = 1; /* we already read the version byte */
187
188     if( i_sig_len < 10 ) /* signature is at least 10 bytes + the 2 MPIs */
189         return 0;
190
191     p_sig->type = *p_buf++; i_read++;
192
193     p_sig->public_key_algo = *p_buf++; i_read++;
194     if (p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA )
195             return 0;
196
197     p_sig->digest_algo = *p_buf++; i_read++;
198
199     memcpy( p_sig->specific.v4.hashed_data_len, p_buf, 2 );
200     p_buf += 2; i_read += 2;
201
202     size_t i_hashed_data_len =
203         scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
204     i_read += i_hashed_data_len;
205     if( i_read + 4 > i_sig_len )
206         return 0;
207
208     p_sig->specific.v4.hashed_data = (uint8_t*) malloc( i_hashed_data_len );
209     if( !p_sig->specific.v4.hashed_data )
210         return 0;
211     memcpy( p_sig->specific.v4.hashed_data, p_buf, i_hashed_data_len );
212     p_buf += i_hashed_data_len;
213
214     memcpy( p_sig->specific.v4.unhashed_data_len, p_buf, 2 );
215     p_buf += 2; i_read += 2;
216
217     size_t i_unhashed_data_len =
218         scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
219     i_read += i_unhashed_data_len;
220     if( i_read + 2 > i_sig_len )
221         return 0;
222
223     p_sig->specific.v4.unhashed_data = (uint8_t*) malloc( i_unhashed_data_len );
224     if( !p_sig->specific.v4.unhashed_data )
225         return 0;
226
227     memcpy( p_sig->specific.v4.unhashed_data, p_buf, i_unhashed_data_len );
228     p_buf += i_unhashed_data_len;
229
230     memcpy( p_sig->hash_verification, p_buf, 2 );
231     p_buf += 2; i_read += 2;
232
233     uint8_t *p, *max_pos;
234     p = p_sig->specific.v4.unhashed_data;
235     max_pos = p + scalar_number( p_sig->specific.v4.unhashed_data_len, 2 );
236
237     for( ;; )
238     {
239         if( p > max_pos )
240             return 0;
241
242         size_t i_subpacket_len;
243         if( *p < 192 )
244         {
245             if( p + 1 > max_pos )
246                 return 0;
247             i_subpacket_len = *p++;
248         }
249         else if( *p < 255 )
250         {
251             if( p + 2 > max_pos )
252                 return 0;
253             i_subpacket_len = (*p++ - 192) << 8;
254             i_subpacket_len += *p++ + 192;
255         }
256         else
257         {
258             if( p + 4 > max_pos )
259                 return 0;
260             i_subpacket_len = U32_AT(p);
261             p += 4;
262         }
263
264         if( *p == ISSUER_SUBPACKET )
265         {
266             if( p + 9 > max_pos )
267                 return 0;
268
269             memcpy( &p_sig->issuer_longid, p+1, 8 );
270
271             return i_read;
272         }
273
274         p += i_subpacket_len;
275     }
276 }
277
278
279 static int parse_signature_packet( signature_packet_t *p_sig,
280                                    const uint8_t *p_buf, size_t i_packet_len )
281 {
282     if( !i_packet_len ) /* 1st sanity check, we need at least the version */
283         return VLC_EGENERIC;
284
285     p_sig->version = *p_buf++;
286
287     size_t i_read;
288     switch( p_sig->version )
289     {
290         case 3:
291             i_read = parse_signature_v3_packet( p_sig, p_buf, i_packet_len );
292             break;
293         case 4:
294             p_sig->specific.v4.hashed_data = NULL;
295             p_sig->specific.v4.unhashed_data = NULL;
296             i_read = parse_signature_v4_packet( p_sig, p_buf, i_packet_len );
297             break;
298         default:
299             return VLC_EGENERIC;
300     }
301
302     if( i_read == 0 ) /* signature packet parsing has failed */
303         goto error;
304
305     if( p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA )
306         goto error;
307
308     switch( p_sig->type )
309     {
310         case BINARY_SIGNATURE:
311         case TEXT_SIGNATURE:
312         case GENERIC_KEY_SIGNATURE:
313         case PERSONA_KEY_SIGNATURE:
314         case CASUAL_KEY_SIGNATURE:
315         case POSITIVE_KEY_SIGNATURE:
316             break;
317         default:
318             goto error;
319     }
320
321     p_buf--; /* rewind to the version byte */
322     p_buf += i_read;
323
324     if( p_sig->public_key_algo == GCRY_PK_DSA ) {
325         READ_MPI(p_sig->algo_specific.dsa.r, 256);
326         READ_MPI(p_sig->algo_specific.dsa.s, 256);
327     } else if ( p_sig->public_key_algo == GCRY_PK_RSA ) {
328         READ_MPI(p_sig->algo_specific.rsa.s, 4096);
329     } else
330         goto error;
331
332     assert( i_read == i_packet_len );
333     if( i_read < i_packet_len ) /* some extra data, hm ? */
334         goto error;
335
336     return VLC_SUCCESS;
337
338 error:
339
340     if( p_sig->version == 4 )
341     {
342         free( p_sig->specific.v4.hashed_data );
343         free( p_sig->specific.v4.unhashed_data );
344     }
345
346     return VLC_EGENERIC;
347 }
348
349
350 /*
351  * crc_octets() was lamely copied from rfc 2440
352  * Copyright (C) The Internet Society (1998).  All Rights Reserved.
353  */
354 #define CRC24_INIT 0xB704CEL
355 #define CRC24_POLY 0x1864CFBL
356
357 static long crc_octets( uint8_t *octets, size_t len )
358 {
359     long crc = CRC24_INIT;
360     int i;
361     while (len--)
362     {
363         crc ^= (*octets++) << 16;
364         for (i = 0; i < 8; i++)
365         {
366             crc <<= 1;
367             if (crc & 0x1000000)
368                 crc ^= CRC24_POLY;
369         }
370     }
371     return crc & 0xFFFFFFL;
372 }
373
374
375 /*
376  * Transform an armored document in binary format
377  * Used on public keys and signatures
378  */
379 static int pgp_unarmor( const char *p_ibuf, size_t i_ibuf_len,
380                         uint8_t *p_obuf, size_t i_obuf_len )
381 {
382     const char *p_ipos = p_ibuf;
383     uint8_t *p_opos = p_obuf;
384     int i_end = 0;
385     int i_header_skipped = 0;
386
387     while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' )
388     {
389         if( *p_ipos == '\r' || *p_ipos == '\n' )
390         {
391             p_ipos++;
392             continue;
393         }
394
395         size_t i_line_len = strcspn( p_ipos, "\r\n" );
396         if( i_line_len == 0 )
397             continue;
398
399         if( !i_header_skipped )
400         {
401             if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) )
402                 i_header_skipped = 1;
403
404             p_ipos += i_line_len + 1;
405             continue;
406         }
407
408         if( !strncmp( p_ipos, "Version:", 8 ) )
409         {
410             p_ipos += i_line_len + 1;
411             continue;
412         }
413
414         if( p_ipos[i_line_len - 1] == '=' )
415         {
416             i_end = 1;
417         }
418
419         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
420                         p_obuf - p_opos + i_obuf_len, p_ipos );
421         p_ipos += i_line_len + 1;
422     }
423
424     /* XXX: the CRC is OPTIONAL, really require it ? */
425     if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' )
426         return 0;
427
428     uint8_t p_crc[3];
429     if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 )
430         return 0;
431
432     long l_crc = crc_octets( p_obuf, p_opos - p_obuf );
433     long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2];
434
435     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
436 }
437
438 static int rsa_pkcs1_encode_sig(gcry_mpi_t *r_result, size_t size,
439                                 const uint8_t *hash, int algo)
440 {
441     uint8_t asn[100];
442     uint8_t frame[4096/8];
443
444     size_t asnlen = sizeof(asn);
445     size_t hashlen = gcry_md_get_algo_dlen(algo);
446
447     if (gcry_md_algo_info(algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
448         return VLC_EGENERIC;
449
450     if (!hashlen || hashlen + asnlen + 4 > size)
451         return VLC_EGENERIC;
452
453     frame[0] = 0;
454     frame[1] = 1; /* block type */
455     int pad = size - hashlen - asnlen - 3 ;
456     memset (&frame[2], 0xff, pad );
457     frame[2+pad] = 0;
458     memcpy(&frame[3+pad], asn, asnlen);
459     memcpy(&frame[3+pad+asnlen], hash, hashlen);
460
461     if (gcry_mpi_scan(r_result, GCRYMPI_FMT_USG, frame, size, &size))
462         return VLC_EGENERIC;
463     return VLC_SUCCESS;
464 }
465
466 /*
467  * Verify an OpenPGP signature made with some RSA public key
468  */
469 static int verify_signature_rsa( signature_packet_t *sign, public_key_packet_t *p_key,
470                       uint8_t *p_hash )
471 {
472     int ret = VLC_EGENERIC;
473     /* the data to be verified (a hash) */
474     const char *hash_sexp_s = "(data(flags raw)(value %m))";
475     /* the public key */
476     const char *key_sexp_s = "(public-key(rsa(n %m)(e %m)))";
477     /* the signature */
478     const char *sig_sexp_s = "(sig-val(rsa(s%m)))";
479
480     size_t erroff;
481     gcry_mpi_t n, e, s, hash;
482     n = e = s = hash = NULL;
483     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
484     key_sexp = hash_sexp = sig_sexp = NULL;
485
486     int i_n_len = mpi_len( p_key->sig.rsa.n );
487     int i_e_len = mpi_len( p_key->sig.rsa.e );
488     if( gcry_mpi_scan( &n, GCRYMPI_FMT_USG, p_key->sig.rsa.n + 2, i_n_len, NULL ) ||
489         gcry_mpi_scan( &e, GCRYMPI_FMT_USG, p_key->sig.rsa.e + 2, i_e_len, NULL ) ||
490         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, n, e ) )
491         goto out;
492
493     uint8_t *p_s = sign->algo_specific.rsa.s;
494     int i_s_len = mpi_len( p_s );
495     if( gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
496         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, s ) )
497         goto out;
498
499     if( rsa_pkcs1_encode_sig (&hash, i_n_len, p_hash, sign->digest_algo) ||
500         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
501         goto out;
502
503     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
504         goto out;
505
506     ret = VLC_SUCCESS;
507
508 out:
509     if( n ) gcry_mpi_release( n );
510     if( e ) gcry_mpi_release( e );
511     if( s ) gcry_mpi_release( s );
512     if( hash ) gcry_mpi_release( hash );
513     if( key_sexp ) gcry_sexp_release( key_sexp );
514     if( sig_sexp ) gcry_sexp_release( sig_sexp );
515     if( hash_sexp ) gcry_sexp_release( hash_sexp );
516     return ret;
517 }
518
519 /*
520  * Verify an OpenPGP signature made with some DSA public key
521  */
522 static int verify_signature_dsa( signature_packet_t *sign, public_key_packet_t *p_key,
523                       uint8_t *p_hash )
524 {
525     int ret = VLC_EGENERIC;
526
527     /* the data to be verified (a hash) */
528     const char *hash_sexp_s = "(data(flags raw)(value %m))";
529     /* the public key */
530     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
531     /* the signature */
532     const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))";
533
534     size_t erroff;
535     gcry_mpi_t p, q, g, y, r, s, hash;
536     p = q = g = y = r = s = hash = NULL;
537     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
538     key_sexp = hash_sexp = sig_sexp = NULL;
539
540     int i_p_len = mpi_len( p_key->sig.dsa.p );
541     int i_q_len = mpi_len( p_key->sig.dsa.q );
542     int i_g_len = mpi_len( p_key->sig.dsa.g );
543     int i_y_len = mpi_len( p_key->sig.dsa.y );
544     if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->sig.dsa.p + 2, i_p_len, NULL ) ||
545         gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->sig.dsa.q + 2, i_q_len, NULL ) ||
546         gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->sig.dsa.g + 2, i_g_len, NULL ) ||
547         gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->sig.dsa.y + 2, i_y_len, NULL ) ||
548         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
549         goto out;
550
551     uint8_t *p_r = sign->algo_specific.dsa.r;
552     uint8_t *p_s = sign->algo_specific.dsa.s;
553     int i_r_len = mpi_len( p_r );
554     int i_s_len = mpi_len( p_s );
555     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
556         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
557         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
558         goto out;
559
560     int i_hash_len = gcry_md_get_algo_dlen (sign->digest_algo);
561     if (i_hash_len > i_q_len)
562         i_hash_len = i_q_len;
563     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
564         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
565         goto out;
566
567     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
568         goto out;
569
570     ret = VLC_SUCCESS;
571
572 out:
573     if( p ) gcry_mpi_release( p );
574     if( q ) gcry_mpi_release( q );
575     if( g ) gcry_mpi_release( g );
576     if( y ) gcry_mpi_release( y );
577     if( r ) gcry_mpi_release( r );
578     if( s ) gcry_mpi_release( s );
579     if( hash ) gcry_mpi_release( hash );
580     if( key_sexp ) gcry_sexp_release( key_sexp );
581     if( sig_sexp ) gcry_sexp_release( sig_sexp );
582     if( hash_sexp ) gcry_sexp_release( hash_sexp );
583
584     return ret;
585 }
586
587 /*
588  * Verify an OpenPGP signature made with some public key
589  */
590 int verify_signature( signature_packet_t *sign, public_key_packet_t *p_key,
591                       uint8_t *p_hash )
592 {
593     if (sign->public_key_algo == GCRY_PK_DSA)
594         return verify_signature_dsa(sign, p_key, p_hash);
595     else if (sign->public_key_algo == GCRY_PK_RSA)
596         return verify_signature_rsa(sign, p_key, p_hash);
597     else
598         return VLC_EGENERIC;
599 }
600
601
602 /*
603  * fill a public_key_t with public key data, including:
604  *   * public key packet
605  *   * signature packet issued by key which long id is p_sig_issuer
606  *   * user id packet
607  */
608 int parse_public_key( const uint8_t *p_key_data, size_t i_key_len,
609                       public_key_t *p_key, const uint8_t *p_sig_issuer )
610 {
611     const uint8_t *pos = p_key_data;
612     const uint8_t *max_pos = pos + i_key_len;
613
614     int i_status = 0;
615 #define PUBLIC_KEY_FOUND    0x01
616 #define USER_ID_FOUND       0x02
617 #define SIGNATURE_FOUND     0X04
618
619     uint8_t *p_key_unarmored = NULL;
620
621     p_key->psz_username = NULL;
622     p_key->sig.specific.v4.hashed_data = NULL;
623     p_key->sig.specific.v4.unhashed_data = NULL;
624
625     if( !( *pos & 0x80 ) )
626     {   /* first byte is ASCII, unarmoring */
627         p_key_unarmored = (uint8_t*)malloc( i_key_len );
628         if( !p_key_unarmored )
629             return VLC_ENOMEM;
630         int i_len = pgp_unarmor( (char*)p_key_data, i_key_len,
631                                  p_key_unarmored, i_key_len );
632
633         if( i_len == 0 )
634             goto error;
635
636         pos = p_key_unarmored;
637         max_pos = pos + i_len;
638     }
639
640     while( pos < max_pos )
641     {
642         if( !(*pos & 0x80) || *pos & 0x40 )
643             goto error;
644
645         int i_type = packet_type( *pos );
646
647         int i_header_len = packet_header_len( *pos++ );
648         if( pos + i_header_len > max_pos ||
649             ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) )
650             goto error;
651
652         int i_packet_len = scalar_number( pos, i_header_len );
653         pos += i_header_len;
654
655         if( pos + i_packet_len > max_pos )
656             goto error;
657
658         switch( i_type )
659         {
660             case PUBLIC_KEY_PACKET:
661                 i_status |= PUBLIC_KEY_FOUND;
662                 if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS )
663                     goto error;
664                 break;
665
666             case SIGNATURE_PACKET: /* we accept only v4 signatures here */
667                 if( i_status & SIGNATURE_FOUND || !p_sig_issuer )
668                     break;
669                 int i_ret = parse_signature_packet( &p_key->sig, pos,
670                                                     i_packet_len );
671                 if( i_ret == VLC_SUCCESS )
672                 {
673                     if( p_key->sig.version != 4 )
674                         break;
675                     if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) )
676                     {
677                         free( p_key->sig.specific.v4.hashed_data );
678                         free( p_key->sig.specific.v4.unhashed_data );
679                         p_key->sig.specific.v4.hashed_data = NULL;
680                         p_key->sig.specific.v4.unhashed_data = NULL;
681                         break;
682                     }
683                     i_status |= SIGNATURE_FOUND;
684                 }
685                 break;
686
687             case USER_ID_PACKET:
688                 if( p_key->psz_username ) /* save only the first User ID */
689                     break;
690                 i_status |= USER_ID_FOUND;
691                 p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1);
692                 if( !p_key->psz_username )
693                     goto error;
694
695                 memcpy( p_key->psz_username, pos, i_packet_len );
696                 p_key->psz_username[i_packet_len] = '\0';
697                 break;
698
699             default:
700                 break;
701         }
702         pos += i_packet_len;
703     }
704     free( p_key_unarmored );
705
706     if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) )
707         return VLC_EGENERIC;
708
709     if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) )
710         return VLC_EGENERIC;
711
712     return VLC_SUCCESS;
713
714 error:
715     if( p_key->sig.version == 4 )
716     {
717         free( p_key->sig.specific.v4.hashed_data );
718         free( p_key->sig.specific.v4.unhashed_data );
719     }
720     free( p_key->psz_username );
721     free( p_key_unarmored );
722     return VLC_EGENERIC;
723 }
724
725
726 /* hash a binary file */
727 static int hash_from_binary_file( const char *psz_file, gcry_md_hd_t hd )
728 {
729     uint8_t buffer[4096];
730     size_t i_read;
731
732     FILE *f = vlc_fopen( psz_file, "r" );
733     if( !f )
734         return -1;
735
736     while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 )
737         gcry_md_write( hd, buffer, i_read );
738
739     fclose( f );
740
741     return 0;
742 }
743
744
745 /* final part of the hash */
746 static uint8_t *hash_finish( gcry_md_hd_t hd, signature_packet_t *p_sig )
747 {
748     if( p_sig->version == 3 )
749     {
750         gcry_md_putc( hd, p_sig->type );
751         gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 );
752     }
753     else if( p_sig->version == 4 )
754     {
755         gcry_md_putc( hd, p_sig->version );
756         gcry_md_putc( hd, p_sig->type );
757         gcry_md_putc( hd, p_sig->public_key_algo );
758         gcry_md_putc( hd, p_sig->digest_algo );
759         gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 );
760         size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
761         gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len );
762
763         gcry_md_putc( hd, 0x04 );
764         gcry_md_putc( hd, 0xFF );
765
766         i_len += 6; /* hashed data + 6 bytes header */
767
768         gcry_md_putc( hd, (i_len >> 24) & 0xff );
769         gcry_md_putc( hd, (i_len >> 16) & 0xff );
770         gcry_md_putc( hd, (i_len >> 8) & 0xff );
771         gcry_md_putc( hd, (i_len) & 0xff );
772     }
773     else
774     {   /* RFC 4880 only tells about versions 3 and 4 */
775         return NULL;
776     }
777
778     gcry_md_final( hd );
779
780     uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, p_sig->digest_algo) ;
781     unsigned int hash_len = gcry_md_get_algo_dlen (p_sig->digest_algo);
782     uint8_t *p_hash = malloc(hash_len);
783     if( p_hash )
784         memcpy(p_hash, p_tmp, hash_len);
785     gcry_md_close( hd );
786     return p_hash;
787 }
788
789
790 /*
791  * return a hash of a text
792  */
793 uint8_t *hash_from_text( const char *psz_string,
794         signature_packet_t *p_sig )
795 {
796     gcry_md_hd_t hd;
797     if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
798         return NULL;
799
800     if( p_sig->type == TEXT_SIGNATURE )
801     while( *psz_string )
802     {
803         size_t i_len = strcspn( psz_string, "\r\n" );
804
805         if( i_len )
806         {
807             gcry_md_write( hd, psz_string, i_len );
808             psz_string += i_len;
809         }
810         gcry_md_putc( hd, '\r' );
811         gcry_md_putc( hd, '\n' );
812
813         if( *psz_string == '\r' )
814             psz_string++;
815         if( *psz_string == '\n' )
816             psz_string++;
817     }
818     else
819         gcry_md_write( hd, psz_string, strlen( psz_string ) );
820
821     return hash_finish( hd, p_sig );
822 }
823
824
825 /*
826  * return a hash of a file
827  */
828 uint8_t *hash_from_file( const char *psz_file, signature_packet_t *p_sig )
829 {
830     gcry_md_hd_t hd;
831     if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
832         return NULL;
833
834     if( hash_from_binary_file( psz_file, hd ) < 0 )
835     {
836         gcry_md_close( hd );
837         return NULL;
838     }
839
840     return hash_finish( hd, p_sig );
841 }
842
843
844 /*
845  * Generate a hash on a public key, to verify a signature made on that hash
846  * Note that we need the signature (v4) to compute the hash
847  */
848 uint8_t *hash_from_public_key( public_key_t *p_pkey )
849 {
850     const uint8_t pk_algo = p_pkey->key.algo;
851     size_t i_size;
852     size_t i_p_len, i_g_len, i_q_len, i_y_len;
853     size_t i_n_len, i_e_len;
854
855     if( p_pkey->sig.version != 4 )
856         return NULL;
857
858     if( p_pkey->sig.type < GENERIC_KEY_SIGNATURE ||
859         p_pkey->sig.type > POSITIVE_KEY_SIGNATURE )
860         return NULL;
861
862     gcry_error_t error = 0;
863     gcry_md_hd_t hd;
864
865     if (pk_algo == GCRY_PK_DSA) {
866         i_p_len = mpi_len( p_pkey->key.sig.dsa.p );
867         i_g_len = mpi_len( p_pkey->key.sig.dsa.g );
868         i_q_len = mpi_len( p_pkey->key.sig.dsa.q );
869         i_y_len = mpi_len( p_pkey->key.sig.dsa.y );
870
871         i_size = 6 + 2*4 + i_p_len + i_g_len + i_q_len + i_y_len;
872     } else if (pk_algo == GCRY_PK_RSA) {
873         i_n_len = mpi_len( p_pkey->key.sig.rsa.n );
874         i_e_len = mpi_len( p_pkey->key.sig.rsa.e );
875
876         i_size = 6 + 2*2 + i_n_len + i_e_len;
877     } else
878         return NULL;
879
880     error = gcry_md_open( &hd, p_pkey->sig.digest_algo, 0 );
881     if( error )
882         return NULL;
883
884     gcry_md_putc( hd, 0x99 );
885
886     gcry_md_putc( hd, (i_size >> 8) & 0xff );
887     gcry_md_putc( hd, i_size & 0xff );
888
889     gcry_md_putc( hd, p_pkey->key.version );
890     gcry_md_write( hd, p_pkey->key.timestamp, 4 );
891     gcry_md_putc( hd, p_pkey->key.algo );
892
893     if (pk_algo == GCRY_PK_DSA) {
894         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.p, 2 + i_p_len );
895         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.q, 2 + i_q_len );
896         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.g, 2 + i_g_len );
897         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.y, 2 + i_y_len );
898     } else if (pk_algo == GCRY_PK_RSA) {
899         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.n, 2 + i_n_len );
900         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.e, 2 + i_e_len );
901     }
902
903     gcry_md_putc( hd, 0xb4 );
904
905     size_t i_len = strlen((char*)p_pkey->psz_username);
906
907     gcry_md_putc( hd, (i_len >> 24) & 0xff );
908     gcry_md_putc( hd, (i_len >> 16) & 0xff );
909     gcry_md_putc( hd, (i_len >> 8) & 0xff );
910     gcry_md_putc( hd, (i_len) & 0xff );
911
912     gcry_md_write( hd, p_pkey->psz_username, i_len );
913
914     uint8_t *p_hash = hash_finish( hd, &p_pkey->sig );
915     if( !p_hash ||
916         p_hash[0] != p_pkey->sig.hash_verification[0] ||
917         p_hash[1] != p_pkey->sig.hash_verification[1] )
918     {
919         free(p_hash);
920         return NULL;
921     }
922
923     return p_hash;
924 }
925
926
927 /*
928  * download a public key (the last one) from videolan server, and parse it
929  */
930 public_key_t *download_key( vlc_object_t *p_this,
931                     const uint8_t *p_longid, const uint8_t *p_signature_issuer )
932 {
933     char *psz_url;
934     if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc",
935                     p_longid[0], p_longid[1], p_longid[2], p_longid[3],
936                     p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 )
937         return NULL;
938
939     stream_t *p_stream = stream_UrlNew( p_this, psz_url );
940     free( psz_url );
941     if( !p_stream )
942         return NULL;
943
944     int64_t i_size = stream_Size( p_stream );
945     if( i_size < 0 )
946     {
947         stream_Delete( p_stream );
948         return NULL;
949     }
950
951     uint8_t *p_buf = (uint8_t*)malloc( i_size );
952     if( !p_buf )
953     {
954         stream_Delete( p_stream );
955         return NULL;
956     }
957
958     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
959     stream_Delete( p_stream );
960
961     if( i_read != (int)i_size )
962     {
963         msg_Dbg( p_this, "Couldn't read full GPG key" );
964         free( p_buf );
965         return NULL;
966     }
967
968     public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) );
969     if( !p_pkey )
970     {
971         free( p_buf );
972         return NULL;
973     }
974
975     memcpy( p_pkey->longid, p_longid, 8 );
976
977     int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer );
978     free( p_buf );
979
980     if( i_error != VLC_SUCCESS )
981     {
982         msg_Dbg( p_this, "Couldn't parse GPG key" );
983         free( p_pkey );
984         return NULL;
985     }
986
987     return p_pkey;
988 }
989
990
991 /*
992  * Download the signature associated to a document or a binary file.
993  * We're given the file's url, we just append ".asc" to it and download
994  */
995 int download_signature( vlc_object_t *p_this, signature_packet_t *p_sig,
996                         const char *psz_url )
997 {
998     char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */
999     if( !psz_sig )
1000         return VLC_ENOMEM;
1001
1002     strcpy( psz_sig, psz_url );
1003     strcat( psz_sig, ".asc" );
1004
1005     stream_t *p_stream = stream_UrlNew( p_this, psz_sig );
1006     free( psz_sig );
1007
1008     if( !p_stream )
1009         return VLC_ENOMEM;
1010
1011     int64_t i_size = stream_Size( p_stream );
1012
1013     msg_Dbg( p_this, "Downloading signature (%"PRId64" bytes)", i_size );
1014     uint8_t *p_buf = (uint8_t*)malloc( i_size );
1015     if( !p_buf )
1016     {
1017         stream_Delete( p_stream );
1018         return VLC_ENOMEM;
1019     }
1020
1021     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
1022
1023     stream_Delete( p_stream );
1024
1025     if( i_read != (int)i_size )
1026     {
1027         msg_Dbg( p_this,
1028             "Couldn't download full signature (only %d bytes)", i_read );
1029         free( p_buf );
1030         return VLC_EGENERIC;
1031     }
1032
1033     if( (uint8_t)*p_buf < 0x80 ) /* ASCII */
1034     {
1035         msg_Dbg( p_this, "Unarmoring signature" );
1036
1037         uint8_t* p_unarmored = (uint8_t*) malloc( ( i_size * 3 ) / 4 + 1 );
1038         if( !p_unarmored )
1039         {
1040             free( p_buf );
1041             return VLC_EGENERIC;
1042         }
1043
1044         int i_bytes = pgp_unarmor( (char*)p_buf, i_size, p_unarmored, i_size );
1045         free( p_buf );
1046
1047         p_buf = p_unarmored;
1048         i_size = i_bytes;
1049
1050         if( i_bytes < 2 )
1051         {
1052             free( p_buf );
1053             msg_Dbg( p_this, "Unarmoring failed : corrupted signature ?" );
1054             return VLC_EGENERIC;
1055         }
1056     }
1057
1058     if( packet_type( *p_buf ) != SIGNATURE_PACKET )
1059     {
1060         msg_Dbg( p_this, "Not a signature: %d", *p_buf );
1061         free( p_buf );
1062         return VLC_EGENERIC;
1063     }
1064
1065     size_t i_header_len = packet_header_len( *p_buf );
1066     if( ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ||
1067         i_header_len + 1 > (size_t)i_size )
1068     {
1069         free( p_buf );
1070         msg_Dbg( p_this, "Invalid signature packet header" );
1071         return VLC_EGENERIC;
1072     }
1073
1074     size_t i_len = scalar_number( p_buf+1, i_header_len );
1075     if( i_len + i_header_len + 1 != (size_t)i_size )
1076     {
1077         free( p_buf );
1078         msg_Dbg( p_this, "Invalid signature packet" );
1079         return VLC_EGENERIC;
1080     }
1081
1082     int i_ret = parse_signature_packet( p_sig, p_buf+1+i_header_len, i_len );
1083     free( p_buf );
1084     if( i_ret != VLC_SUCCESS )
1085     {
1086         msg_Dbg( p_this, "Couldn't parse signature" );
1087         return i_ret;
1088     }
1089
1090     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
1091     {
1092         msg_Dbg( p_this, "Invalid signature type: %d", p_sig->type );
1093         if( p_sig->version == 4 )
1094         {
1095             free( p_sig->specific.v4.hashed_data );
1096             free( p_sig->specific.v4.unhashed_data );
1097         }
1098         return VLC_EGENERIC;
1099     }
1100
1101     return VLC_SUCCESS;
1102 }
1103
1104 #endif /* UPDATE_CHECK */