]> git.sesse.net Git - vlc/blob - src/misc/update_crypto.c
update: RSA support
[vlc] / 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 = *++p << 24;
261             i_subpacket_len += *++p << 16;
262             i_subpacket_len += *++p << 8;
263             i_subpacket_len += *++p;
264         }
265
266         if( *p == ISSUER_SUBPACKET )
267         {
268             if( p + 9 > max_pos )
269                 return 0;
270
271             memcpy( &p_sig->issuer_longid, p+1, 8 );
272
273             return i_read;
274         }
275
276         p += i_subpacket_len;
277     }
278 }
279
280
281 static int parse_signature_packet( signature_packet_t *p_sig,
282                                    const uint8_t *p_buf, size_t i_packet_len )
283 {
284     if( !i_packet_len ) /* 1st sanity check, we need at least the version */
285         return VLC_EGENERIC;
286
287     p_sig->version = *p_buf++;
288
289     size_t i_read;
290     switch( p_sig->version )
291     {
292         case 3:
293             i_read = parse_signature_v3_packet( p_sig, p_buf, i_packet_len );
294             break;
295         case 4:
296             p_sig->specific.v4.hashed_data = NULL;
297             p_sig->specific.v4.unhashed_data = NULL;
298             i_read = parse_signature_v4_packet( p_sig, p_buf, i_packet_len );
299             break;
300         default:
301             return VLC_EGENERIC;
302     }
303
304     if( i_read == 0 ) /* signature packet parsing has failed */
305         goto error;
306
307     if( p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA )
308         goto error;
309
310     switch( p_sig->type )
311     {
312         case BINARY_SIGNATURE:
313         case TEXT_SIGNATURE:
314         case GENERIC_KEY_SIGNATURE:
315         case PERSONA_KEY_SIGNATURE:
316         case CASUAL_KEY_SIGNATURE:
317         case POSITIVE_KEY_SIGNATURE:
318             break;
319         default:
320             goto error;
321     }
322
323     p_buf--; /* rewind to the version byte */
324     p_buf += i_read;
325
326     if( p_sig->public_key_algo == GCRY_PK_DSA ) {
327         READ_MPI(p_sig->algo_specific.dsa.r, 256);
328         READ_MPI(p_sig->algo_specific.dsa.s, 256);
329     } else if ( p_sig->public_key_algo == GCRY_PK_RSA ) {
330         READ_MPI(p_sig->algo_specific.rsa.s, 4096);
331     } else
332         goto error;
333
334     assert( i_read == i_packet_len );
335     if( i_read < i_packet_len ) /* some extra data, hm ? */
336         goto error;
337
338     return VLC_SUCCESS;
339
340 error:
341
342     if( p_sig->version == 4 )
343     {
344         free( p_sig->specific.v4.hashed_data );
345         free( p_sig->specific.v4.unhashed_data );
346     }
347
348     return VLC_EGENERIC;
349 }
350
351
352 /*
353  * crc_octets() was lamely copied from rfc 2440
354  * Copyright (C) The Internet Society (1998).  All Rights Reserved.
355  */
356 #define CRC24_INIT 0xB704CEL
357 #define CRC24_POLY 0x1864CFBL
358
359 static long crc_octets( uint8_t *octets, size_t len )
360 {
361     long crc = CRC24_INIT;
362     int i;
363     while (len--)
364     {
365         crc ^= (*octets++) << 16;
366         for (i = 0; i < 8; i++)
367         {
368             crc <<= 1;
369             if (crc & 0x1000000)
370                 crc ^= CRC24_POLY;
371         }
372     }
373     return crc & 0xFFFFFFL;
374 }
375
376
377 /*
378  * Transform an armored document in binary format
379  * Used on public keys and signatures
380  */
381 static int pgp_unarmor( const char *p_ibuf, size_t i_ibuf_len,
382                         uint8_t *p_obuf, size_t i_obuf_len )
383 {
384     const char *p_ipos = p_ibuf;
385     uint8_t *p_opos = p_obuf;
386     int i_end = 0;
387     int i_header_skipped = 0;
388
389     while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' )
390     {
391         if( *p_ipos == '\r' || *p_ipos == '\n' )
392         {
393             p_ipos++;
394             continue;
395         }
396
397         size_t i_line_len = strcspn( p_ipos, "\r\n" );
398         if( i_line_len == 0 )
399             continue;
400
401         if( !i_header_skipped )
402         {
403             if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) )
404                 i_header_skipped = 1;
405
406             p_ipos += i_line_len + 1;
407             continue;
408         }
409
410         if( !strncmp( p_ipos, "Version:", 8 ) )
411         {
412             p_ipos += i_line_len + 1;
413             continue;
414         }
415
416         if( p_ipos[i_line_len - 1] == '=' )
417         {
418             i_end = 1;
419         }
420
421         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
422                         p_obuf - p_opos + i_obuf_len, p_ipos );
423         p_ipos += i_line_len + 1;
424     }
425
426     /* XXX: the CRC is OPTIONAL, really require it ? */
427     if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' )
428         return 0;
429
430     uint8_t p_crc[3];
431     if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 )
432         return 0;
433
434     long l_crc = crc_octets( p_obuf, p_opos - p_obuf );
435     long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2];
436
437     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
438 }
439
440 static int rsa_pkcs1_encode_sig(gcry_mpi_t *r_result, size_t size,
441                                 const uint8_t *hash, int algo)
442 {
443     uint8_t asn[100];
444     uint8_t frame[4096/8];
445
446     size_t asnlen = sizeof(asn);
447     size_t hashlen = gcry_md_get_algo_dlen(algo);
448
449     if (gcry_md_algo_info(algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
450         return VLC_EGENERIC;
451
452     if (!hashlen || hashlen + asnlen + 4 > size)
453         return VLC_EGENERIC;
454
455     frame[0] = 0;
456     frame[1] = 1; /* block type */
457     int pad = size - hashlen - asnlen - 3 ;
458     memset (&frame[2], 0xff, pad );
459     frame[2+pad] = 0;
460     memcpy(&frame[3+pad], asn, asnlen);
461     memcpy(&frame[3+pad+asnlen], hash, hashlen);
462
463     if (gcry_mpi_scan(r_result, GCRYMPI_FMT_USG, frame, size, &size))
464         return VLC_EGENERIC;
465     return VLC_SUCCESS;
466 }
467
468 /*
469  * Verify an OpenPGP signature made with some RSA public key
470  */
471 static int verify_signature_rsa( signature_packet_t *sign, public_key_packet_t *p_key,
472                       uint8_t *p_hash )
473 {
474     int ret = VLC_EGENERIC;
475     /* the data to be verified (a hash) */
476     const char *hash_sexp_s = "(data(flags raw)(value %m))";
477     /* the public key */
478     const char *key_sexp_s = "(public-key(rsa(n %m)(e %m)))";
479     /* the signature */
480     const char *sig_sexp_s = "(sig-val(rsa(s%m)))";
481
482     size_t erroff;
483     gcry_mpi_t n, e, s, hash;
484     n = e = s = hash = NULL;
485     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
486     key_sexp = hash_sexp = sig_sexp = NULL;
487
488     int i_n_len = mpi_len( p_key->sig.rsa.n );
489     int i_e_len = mpi_len( p_key->sig.rsa.e );
490     if( gcry_mpi_scan( &n, GCRYMPI_FMT_USG, p_key->sig.rsa.n + 2, i_n_len, NULL ) ||
491         gcry_mpi_scan( &e, GCRYMPI_FMT_USG, p_key->sig.rsa.e + 2, i_e_len, NULL ) ||
492         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, n, e ) )
493         goto out;
494
495     uint8_t *p_s = sign->algo_specific.rsa.s;
496     int i_s_len = mpi_len( p_s );
497     if( gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
498         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, s ) )
499         goto out;
500
501     if( rsa_pkcs1_encode_sig (&hash, i_n_len, p_hash, sign->digest_algo) ||
502         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
503         goto out;
504
505     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
506         goto out;
507
508     ret = VLC_SUCCESS;
509
510 out:
511     if( n ) gcry_mpi_release( n );
512     if( e ) gcry_mpi_release( e );
513     if( s ) gcry_mpi_release( s );
514     if( hash ) gcry_mpi_release( hash );
515     if( key_sexp ) gcry_sexp_release( key_sexp );
516     if( sig_sexp ) gcry_sexp_release( sig_sexp );
517     if( hash_sexp ) gcry_sexp_release( hash_sexp );
518     return ret;
519 }
520
521 /*
522  * Verify an OpenPGP signature made with some DSA public key
523  */
524 static int verify_signature_dsa( signature_packet_t *sign, public_key_packet_t *p_key,
525                       uint8_t *p_hash )
526 {
527     int ret = VLC_EGENERIC;
528
529     /* the data to be verified (a hash) */
530     const char *hash_sexp_s = "(data(flags raw)(value %m))";
531     /* the public key */
532     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
533     /* the signature */
534     const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))";
535
536     size_t erroff;
537     gcry_mpi_t p, q, g, y, r, s, hash;
538     p = q = g = y = r = s = hash = NULL;
539     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
540     key_sexp = hash_sexp = sig_sexp = NULL;
541
542     int i_p_len = mpi_len( p_key->sig.dsa.p );
543     int i_q_len = mpi_len( p_key->sig.dsa.q );
544     int i_g_len = mpi_len( p_key->sig.dsa.g );
545     int i_y_len = mpi_len( p_key->sig.dsa.y );
546     if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->sig.dsa.p + 2, i_p_len, NULL ) ||
547         gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->sig.dsa.q + 2, i_q_len, NULL ) ||
548         gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->sig.dsa.g + 2, i_g_len, NULL ) ||
549         gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->sig.dsa.y + 2, i_y_len, NULL ) ||
550         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
551         goto out;
552
553     uint8_t *p_r = sign->algo_specific.dsa.r;
554     uint8_t *p_s = sign->algo_specific.dsa.s;
555     int i_r_len = mpi_len( p_r );
556     int i_s_len = mpi_len( p_s );
557     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
558         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
559         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
560         goto out;
561
562     int i_hash_len = gcry_md_get_algo_dlen (sign->digest_algo);
563     if (i_hash_len > i_q_len)
564         i_hash_len = i_q_len;
565     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
566         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
567         goto out;
568
569     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
570         goto out;
571
572     ret = VLC_SUCCESS;
573
574 out:
575     if( p ) gcry_mpi_release( p );
576     if( q ) gcry_mpi_release( q );
577     if( g ) gcry_mpi_release( g );
578     if( y ) gcry_mpi_release( y );
579     if( r ) gcry_mpi_release( r );
580     if( s ) gcry_mpi_release( s );
581     if( hash ) gcry_mpi_release( hash );
582     if( key_sexp ) gcry_sexp_release( key_sexp );
583     if( sig_sexp ) gcry_sexp_release( sig_sexp );
584     if( hash_sexp ) gcry_sexp_release( hash_sexp );
585
586     return ret;
587 }
588
589 /*
590  * Verify an OpenPGP signature made with some public key
591  */
592 int verify_signature( signature_packet_t *sign, public_key_packet_t *p_key,
593                       uint8_t *p_hash )
594 {
595     if (sign->public_key_algo == GCRY_PK_DSA)
596         return verify_signature_dsa(sign, p_key, p_hash);
597     else if (sign->public_key_algo == GCRY_PK_RSA)
598         return verify_signature_rsa(sign, p_key, p_hash);
599     else
600         return VLC_EGENERIC;
601 }
602
603
604 /*
605  * fill a public_key_t with public key data, including:
606  *   * public key packet
607  *   * signature packet issued by key which long id is p_sig_issuer
608  *   * user id packet
609  */
610 int parse_public_key( const uint8_t *p_key_data, size_t i_key_len,
611                       public_key_t *p_key, const uint8_t *p_sig_issuer )
612 {
613     const uint8_t *pos = p_key_data;
614     const uint8_t *max_pos = pos + i_key_len;
615
616     int i_status = 0;
617 #define PUBLIC_KEY_FOUND    0x01
618 #define USER_ID_FOUND       0x02
619 #define SIGNATURE_FOUND     0X04
620
621     uint8_t *p_key_unarmored = NULL;
622
623     p_key->psz_username = NULL;
624     p_key->sig.specific.v4.hashed_data = NULL;
625     p_key->sig.specific.v4.unhashed_data = NULL;
626
627     if( !( *pos & 0x80 ) )
628     {   /* first byte is ASCII, unarmoring */
629         p_key_unarmored = (uint8_t*)malloc( i_key_len );
630         if( !p_key_unarmored )
631             return VLC_ENOMEM;
632         int i_len = pgp_unarmor( (char*)p_key_data, i_key_len,
633                                  p_key_unarmored, i_key_len );
634
635         if( i_len == 0 )
636             goto error;
637
638         pos = p_key_unarmored;
639         max_pos = pos + i_len;
640     }
641
642     while( pos < max_pos )
643     {
644         if( !(*pos & 0x80) || *pos & 0x40 )
645             goto error;
646
647         int i_type = packet_type( *pos );
648
649         int i_header_len = packet_header_len( *pos++ );
650         if( pos + i_header_len > max_pos ||
651             ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) )
652             goto error;
653
654         int i_packet_len = scalar_number( pos, i_header_len );
655         pos += i_header_len;
656
657         if( pos + i_packet_len > max_pos )
658             goto error;
659
660         switch( i_type )
661         {
662             case PUBLIC_KEY_PACKET:
663                 i_status |= PUBLIC_KEY_FOUND;
664                 if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS )
665                     goto error;
666                 break;
667
668             case SIGNATURE_PACKET: /* we accept only v4 signatures here */
669                 if( i_status & SIGNATURE_FOUND || !p_sig_issuer )
670                     break;
671                 int i_ret = parse_signature_packet( &p_key->sig, pos,
672                                                     i_packet_len );
673                 if( i_ret == VLC_SUCCESS )
674                 {
675                     if( p_key->sig.version != 4 )
676                         break;
677                     if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) )
678                     {
679                         free( p_key->sig.specific.v4.hashed_data );
680                         free( p_key->sig.specific.v4.unhashed_data );
681                         p_key->sig.specific.v4.hashed_data = NULL;
682                         p_key->sig.specific.v4.unhashed_data = NULL;
683                         break;
684                     }
685                     i_status |= SIGNATURE_FOUND;
686                 }
687                 break;
688
689             case USER_ID_PACKET:
690                 if( p_key->psz_username ) /* save only the first User ID */
691                     break;
692                 i_status |= USER_ID_FOUND;
693                 p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1);
694                 if( !p_key->psz_username )
695                     goto error;
696
697                 memcpy( p_key->psz_username, pos, i_packet_len );
698                 p_key->psz_username[i_packet_len] = '\0';
699                 break;
700
701             default:
702                 break;
703         }
704         pos += i_packet_len;
705     }
706     free( p_key_unarmored );
707
708     if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) )
709         return VLC_EGENERIC;
710
711     if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) )
712         return VLC_EGENERIC;
713
714     return VLC_SUCCESS;
715
716 error:
717     if( p_key->sig.version == 4 )
718     {
719         free( p_key->sig.specific.v4.hashed_data );
720         free( p_key->sig.specific.v4.unhashed_data );
721     }
722     free( p_key->psz_username );
723     free( p_key_unarmored );
724     return VLC_EGENERIC;
725 }
726
727
728 /* hash a binary file */
729 static int hash_from_binary_file( const char *psz_file, gcry_md_hd_t hd )
730 {
731     uint8_t buffer[4096];
732     size_t i_read;
733
734     FILE *f = vlc_fopen( psz_file, "r" );
735     if( !f )
736         return -1;
737
738     while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 )
739         gcry_md_write( hd, buffer, i_read );
740
741     fclose( f );
742
743     return 0;
744 }
745
746
747 /* final part of the hash */
748 static uint8_t *hash_finish( gcry_md_hd_t hd, signature_packet_t *p_sig )
749 {
750     if( p_sig->version == 3 )
751     {
752         gcry_md_putc( hd, p_sig->type );
753         gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 );
754     }
755     else if( p_sig->version == 4 )
756     {
757         gcry_md_putc( hd, p_sig->version );
758         gcry_md_putc( hd, p_sig->type );
759         gcry_md_putc( hd, p_sig->public_key_algo );
760         gcry_md_putc( hd, p_sig->digest_algo );
761         gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 );
762         size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 );
763         gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len );
764
765         gcry_md_putc( hd, 0x04 );
766         gcry_md_putc( hd, 0xFF );
767
768         i_len += 6; /* hashed data + 6 bytes header */
769
770         gcry_md_putc( hd, (i_len >> 24) & 0xff );
771         gcry_md_putc( hd, (i_len >> 16) & 0xff );
772         gcry_md_putc( hd, (i_len >> 8) & 0xff );
773         gcry_md_putc( hd, (i_len) & 0xff );
774     }
775     else
776     {   /* RFC 4880 only tells about versions 3 and 4 */
777         return NULL;
778     }
779
780     gcry_md_final( hd );
781
782     uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, p_sig->digest_algo) ;
783     unsigned int hash_len = gcry_md_get_algo_dlen (p_sig->digest_algo);
784     uint8_t *p_hash = malloc(hash_len);
785     if( p_hash )
786         memcpy(p_hash, p_tmp, hash_len);
787     gcry_md_close( hd );
788     return p_hash;
789 }
790
791
792 /*
793  * return a hash of a text
794  */
795 uint8_t *hash_from_text( const char *psz_string,
796         signature_packet_t *p_sig )
797 {
798     gcry_md_hd_t hd;
799     if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
800         return NULL;
801
802     if( p_sig->type == TEXT_SIGNATURE )
803     while( *psz_string )
804     {
805         size_t i_len = strcspn( psz_string, "\r\n" );
806
807         if( i_len )
808         {
809             gcry_md_write( hd, psz_string, i_len );
810             psz_string += i_len;
811         }
812         gcry_md_putc( hd, '\r' );
813         gcry_md_putc( hd, '\n' );
814
815         if( *psz_string == '\r' )
816             psz_string++;
817         if( *psz_string == '\n' )
818             psz_string++;
819     }
820     else
821         gcry_md_write( hd, psz_string, strlen( psz_string ) );
822
823     return hash_finish( hd, p_sig );
824 }
825
826
827 /*
828  * return a hash of a file
829  */
830 uint8_t *hash_from_file( const char *psz_file, signature_packet_t *p_sig )
831 {
832     gcry_md_hd_t hd;
833     if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
834         return NULL;
835
836     if( hash_from_binary_file( psz_file, hd ) < 0 )
837     {
838         gcry_md_close( hd );
839         return NULL;
840     }
841
842     return hash_finish( hd, p_sig );
843 }
844
845
846 /*
847  * Generate a hash on a public key, to verify a signature made on that hash
848  * Note that we need the signature (v4) to compute the hash
849  */
850 uint8_t *hash_from_public_key( public_key_t *p_pkey )
851 {
852     const uint8_t pk_algo = p_pkey->key.algo;
853     size_t i_size;
854     size_t i_p_len, i_g_len, i_q_len, i_y_len;
855     size_t i_n_len, i_e_len;
856
857     if( p_pkey->sig.version != 4 )
858         return NULL;
859
860     if( p_pkey->sig.type < GENERIC_KEY_SIGNATURE ||
861         p_pkey->sig.type > POSITIVE_KEY_SIGNATURE )
862         return NULL;
863
864     gcry_error_t error = 0;
865     gcry_md_hd_t hd;
866
867     if (pk_algo == GCRY_PK_DSA) {
868         i_p_len = mpi_len( p_pkey->key.sig.dsa.p );
869         i_g_len = mpi_len( p_pkey->key.sig.dsa.g );
870         i_q_len = mpi_len( p_pkey->key.sig.dsa.q );
871         i_y_len = mpi_len( p_pkey->key.sig.dsa.y );
872
873         i_size = 6 + 2*4 + i_p_len + i_g_len + i_q_len + i_y_len;
874     } else if (pk_algo == GCRY_PK_RSA) {
875         i_n_len = mpi_len( p_pkey->key.sig.rsa.n );
876         i_e_len = mpi_len( p_pkey->key.sig.rsa.e );
877
878         i_size = 6 + 2*2 + i_n_len + i_e_len;
879     } else
880         return NULL;
881
882     error = gcry_md_open( &hd, p_pkey->sig.digest_algo, 0 );
883     if( error )
884         return NULL;
885
886     gcry_md_putc( hd, 0x99 );
887
888     gcry_md_putc( hd, (i_size >> 8) & 0xff );
889     gcry_md_putc( hd, i_size & 0xff );
890
891     gcry_md_putc( hd, p_pkey->key.version );
892     gcry_md_write( hd, p_pkey->key.timestamp, 4 );
893     gcry_md_putc( hd, p_pkey->key.algo );
894
895     if (pk_algo == GCRY_PK_DSA) {
896         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.p, 2 + i_p_len );
897         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.q, 2 + i_q_len );
898         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.g, 2 + i_g_len );
899         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.y, 2 + i_y_len );
900     } else if (pk_algo == GCRY_PK_RSA) {
901         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.n, 2 + i_n_len );
902         gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.e, 2 + i_e_len );
903     }
904
905     gcry_md_putc( hd, 0xb4 );
906
907     size_t i_len = strlen((char*)p_pkey->psz_username);
908
909     gcry_md_putc( hd, (i_len >> 24) & 0xff );
910     gcry_md_putc( hd, (i_len >> 16) & 0xff );
911     gcry_md_putc( hd, (i_len >> 8) & 0xff );
912     gcry_md_putc( hd, (i_len) & 0xff );
913
914     gcry_md_write( hd, p_pkey->psz_username, i_len );
915
916     uint8_t *p_hash = hash_finish( hd, &p_pkey->sig );
917     if( !p_hash ||
918         p_hash[0] != p_pkey->sig.hash_verification[0] ||
919         p_hash[1] != p_pkey->sig.hash_verification[1] )
920     {
921         free(p_hash);
922         return NULL;
923     }
924
925     return p_hash;
926 }
927
928
929 /*
930  * download a public key (the last one) from videolan server, and parse it
931  */
932 public_key_t *download_key( vlc_object_t *p_this,
933                     const uint8_t *p_longid, const uint8_t *p_signature_issuer )
934 {
935     char *psz_url;
936     if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc",
937                     p_longid[0], p_longid[1], p_longid[2], p_longid[3],
938                     p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 )
939         return NULL;
940
941     stream_t *p_stream = stream_UrlNew( p_this, psz_url );
942     free( psz_url );
943     if( !p_stream )
944         return NULL;
945
946     int64_t i_size = stream_Size( p_stream );
947     if( i_size < 0 )
948     {
949         stream_Delete( p_stream );
950         return NULL;
951     }
952
953     uint8_t *p_buf = (uint8_t*)malloc( i_size );
954     if( !p_buf )
955     {
956         stream_Delete( p_stream );
957         return NULL;
958     }
959
960     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
961     stream_Delete( p_stream );
962
963     if( i_read != (int)i_size )
964     {
965         msg_Dbg( p_this, "Couldn't read full GPG key" );
966         free( p_buf );
967         return NULL;
968     }
969
970     public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) );
971     if( !p_pkey )
972     {
973         free( p_buf );
974         return NULL;
975     }
976
977     memcpy( p_pkey->longid, p_longid, 8 );
978
979     int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer );
980     free( p_buf );
981
982     if( i_error != VLC_SUCCESS )
983     {
984         msg_Dbg( p_this, "Couldn't parse GPG key" );
985         free( p_pkey );
986         return NULL;
987     }
988
989     return p_pkey;
990 }
991
992
993 /*
994  * Download the signature associated to a document or a binary file.
995  * We're given the file's url, we just append ".asc" to it and download
996  */
997 int download_signature( vlc_object_t *p_this, signature_packet_t *p_sig,
998                         const char *psz_url )
999 {
1000     char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */
1001     if( !psz_sig )
1002         return VLC_ENOMEM;
1003
1004     strcpy( psz_sig, psz_url );
1005     strcat( psz_sig, ".asc" );
1006
1007     stream_t *p_stream = stream_UrlNew( p_this, psz_sig );
1008     free( psz_sig );
1009
1010     if( !p_stream )
1011         return VLC_ENOMEM;
1012
1013     int64_t i_size = stream_Size( p_stream );
1014
1015     msg_Dbg( p_this, "Downloading signature (%"PRId64" bytes)", i_size );
1016     uint8_t *p_buf = (uint8_t*)malloc( i_size );
1017     if( !p_buf )
1018     {
1019         stream_Delete( p_stream );
1020         return VLC_ENOMEM;
1021     }
1022
1023     int i_read = stream_Read( p_stream, p_buf, (int)i_size );
1024
1025     stream_Delete( p_stream );
1026
1027     if( i_read != (int)i_size )
1028     {
1029         msg_Dbg( p_this,
1030             "Couldn't download full signature (only %d bytes)", i_read );
1031         free( p_buf );
1032         return VLC_EGENERIC;
1033     }
1034
1035     if( (uint8_t)*p_buf < 0x80 ) /* ASCII */
1036     {
1037         msg_Dbg( p_this, "Unarmoring signature" );
1038
1039         uint8_t* p_unarmored = (uint8_t*) malloc( ( i_size * 3 ) / 4 + 1 );
1040         if( !p_unarmored )
1041         {
1042             free( p_buf );
1043             return VLC_EGENERIC;
1044         }
1045
1046         int i_bytes = pgp_unarmor( (char*)p_buf, i_size, p_unarmored, i_size );
1047         free( p_buf );
1048
1049         p_buf = p_unarmored;
1050         i_size = i_bytes;
1051
1052         if( i_bytes < 2 )
1053         {
1054             free( p_buf );
1055             msg_Dbg( p_this, "Unarmoring failed : corrupted signature ?" );
1056             return VLC_EGENERIC;
1057         }
1058     }
1059
1060     if( packet_type( *p_buf ) != SIGNATURE_PACKET )
1061     {
1062         msg_Dbg( p_this, "Not a signature: %d", *p_buf );
1063         free( p_buf );
1064         return VLC_EGENERIC;
1065     }
1066
1067     size_t i_header_len = packet_header_len( *p_buf );
1068     if( ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ||
1069         i_header_len + 1 > (size_t)i_size )
1070     {
1071         free( p_buf );
1072         msg_Dbg( p_this, "Invalid signature packet header" );
1073         return VLC_EGENERIC;
1074     }
1075
1076     size_t i_len = scalar_number( p_buf+1, i_header_len );
1077     if( i_len + i_header_len + 1 != (size_t)i_size )
1078     {
1079         free( p_buf );
1080         msg_Dbg( p_this, "Invalid signature packet" );
1081         return VLC_EGENERIC;
1082     }
1083
1084     int i_ret = parse_signature_packet( p_sig, p_buf+1+i_header_len, i_len );
1085     free( p_buf );
1086     if( i_ret != VLC_SUCCESS )
1087     {
1088         msg_Dbg( p_this, "Couldn't parse signature" );
1089         return i_ret;
1090     }
1091
1092     if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE )
1093     {
1094         msg_Dbg( p_this, "Invalid signature type: %d", p_sig->type );
1095         if( p_sig->version == 4 )
1096         {
1097             free( p_sig->specific.v4.hashed_data );
1098             free( p_sig->specific.v4.unhashed_data );
1099         }
1100         return VLC_EGENERIC;
1101     }
1102
1103     return VLC_SUCCESS;
1104 }
1105
1106 #endif /* UPDATE_CHECK */