]> git.sesse.net Git - vlc/blobdiff - src/misc/update_crypto.c
messages: split logger initialization in two phases
[vlc] / src / misc / update_crypto.c
index 0ef7870569c18fa7da5c9fb1bbbef06c6685035e..f22209c6bb78259d141ea9a4504ba6c4ba4a39dc 100644 (file)
@@ -1,24 +1,24 @@
 /*****************************************************************************
- * update_crypto.c: DSA/SHA1 related functions used for updating
+ * update_crypto.c: OpenPGP related functions used for updating
  *****************************************************************************
- * Copyright © 2008-2009 the VideoLAN team
+ * Copyright © 2008-2009 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Rafaël Carré <funman@videolanorg>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation; either release 2 of the License, or
  * (at your option) any later release.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /**
@@ -55,7 +55,7 @@
 #define packet_header_len( c ) ( ( c & 0x03 ) + 1 ) /* number of bytes in a packet header */
 
 
-static inline int scalar_number( uint8_t *p, int header_len )
+static inline int scalar_number( const uint8_t *p, int header_len )
 {
     assert( header_len == 1 || header_len == 2 || header_len == 4 );
 
@@ -71,18 +71,45 @@ static inline int scalar_number( uint8_t *p, int header_len )
 
 
 /* number of data bytes in a MPI */
-#define mpi_len( mpi ) ( ( scalar_number( mpi, 2 ) + 7 ) / 8 )
+static int mpi_len(const uint8_t *mpi)
+{
+    return (scalar_number(mpi, 2) + 7) / 8;
+}
+
+static size_t read_mpi(uint8_t *dst, const uint8_t *buf, size_t buflen, size_t bits)
+{
+    if (buflen < 2)
+        return 0;
+
+    size_t n = mpi_len(buf);
+
+    if (n * 8 > bits)
+        return 0;
 
+    n += 2;
+
+    if (buflen < n)
+        return 0;
+
+    memcpy(dst, buf, n);
+    return n;
+}
+
+#define READ_MPI(d, bits) do { \
+    size_t n = read_mpi(d, p_buf, i_packet_len - i_read, bits); \
+    if (!n) goto error; \
+    p_buf += n; \
+    i_read += n; \
+} while(0)
 
 /*
  * fill a public_key_packet_t structure from public key packet data
- * verify that it is a version 4 public key packet, using DSA
+ * verify that it is a version 4 public key packet, using DSA or RSA
  */
-static int parse_public_key_packet( public_key_packet_t *p_key, uint8_t *p_buf,
-                                    size_t i_packet_len )
+static int parse_public_key_packet( public_key_packet_t *p_key,
+                                    const uint8_t *p_buf, size_t i_packet_len )
 {
-
-    if( i_packet_len > 418 || i_packet_len < 6 )
+    if( i_packet_len < 6 )
         return VLC_EGENERIC;
 
     size_t i_read = 0;
@@ -95,67 +122,29 @@ static int parse_public_key_packet( public_key_packet_t *p_key, uint8_t *p_buf,
     memcpy( p_key->timestamp, p_buf, 4 ); p_buf += 4; i_read += 4;
 
     p_key->algo      = *p_buf++; i_read++;
-    if( p_key->algo != PUBLIC_KEY_ALGO_DSA )
-        return VLC_EGENERIC;
-
-    /* read p */
-    if( i_read + 2 > i_packet_len )
-        return VLC_EGENERIC;
-
-    int i_p_len = mpi_len( p_buf );
-
-    if( i_p_len > 128 || i_read + 2 + i_p_len > i_packet_len )
-        return VLC_EGENERIC;
-
-    memcpy( p_key->p, p_buf, 2+i_p_len );
-    p_buf += 2+i_p_len; i_read += 2+i_p_len;
-
-    /* read q */
-    if( i_read + 2 > i_packet_len )
-        return VLC_EGENERIC;
-
-    int i_q_len = mpi_len( p_buf );
-
-    if( i_q_len > 20 || i_read+2+i_q_len > i_packet_len )
-        return VLC_EGENERIC;
-
-    memcpy( p_key->q, p_buf, 2+i_q_len );
-    p_buf += 2+i_q_len; i_read += 2+i_q_len;
-
-    /* read g */
-    if( i_read + 2 > i_packet_len )
-        return VLC_EGENERIC;
-
-    int i_g_len = mpi_len( p_buf );
-
-    if( i_g_len > 128 || i_read+2+i_g_len > i_packet_len )
+    if( p_key->algo == GCRY_PK_DSA ) {
+        READ_MPI(p_key->sig.dsa.p, 3072);
+        READ_MPI(p_key->sig.dsa.q, 256);
+        READ_MPI(p_key->sig.dsa.g, 3072);
+        READ_MPI(p_key->sig.dsa.y, 3072);
+    } else if ( p_key->algo == GCRY_PK_RSA ) {
+        READ_MPI(p_key->sig.rsa.n, 4096);
+        READ_MPI(p_key->sig.rsa.e, 4096);
+    } else
         return VLC_EGENERIC;
 
-    memcpy( p_key->g, p_buf, 2+i_g_len );
-    p_buf += 2+i_g_len; i_read += 2+i_g_len;
+    if( i_read == i_packet_len )
+        return VLC_SUCCESS;
 
-    /* read y */
-    if( i_read + 2 > i_packet_len )
-        return VLC_EGENERIC;
-
-    int i_y_len = mpi_len( p_buf );
-
-
-    if( i_y_len > 128 || i_read+2+i_y_len > i_packet_len )
-        return VLC_EGENERIC;
-
-    memcpy( p_key->y, p_buf, 2+i_y_len );
-    i_read += 2+i_y_len;
-
-    if( i_read != i_packet_len ) /* some extra data eh ? */
-        return VLC_EGENERIC;
+    /* some extra data eh ? */
 
-    return VLC_SUCCESS;
+error:
+    return VLC_EGENERIC;
 }
 
 
 static size_t parse_signature_v3_packet( signature_packet_t *p_sig,
-                                      uint8_t *p_buf, size_t i_sig_len )
+                                      const uint8_t *p_buf, size_t i_sig_len )
 {
     size_t i_read = 1; /* we already read the version byte */
 
@@ -189,10 +178,10 @@ static size_t parse_signature_v3_packet( signature_packet_t *p_sig,
 
 /*
  * fill a signature_packet_v4_t from signature packet data
- * verify that it was used with a DSA public key, using SHA-1 digest
+ * verify that it was used with a DSA or RSA public key
  */
 static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
-                                      uint8_t *p_buf, size_t i_sig_len )
+                                      const uint8_t *p_buf, size_t i_sig_len )
 {
     size_t i_read = 1; /* we already read the version byte */
 
@@ -202,6 +191,8 @@ static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
     p_sig->type = *p_buf++; i_read++;
 
     p_sig->public_key_algo = *p_buf++; i_read++;
+    if (p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA )
+            return 0;
 
     p_sig->digest_algo = *p_buf++; i_read++;
 
@@ -264,12 +255,10 @@ static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
         }
         else
         {
-            if( p + 4 > max_pos )
+            if( ++p + 4 > max_pos )
                 return 0;
-            i_subpacket_len = *++p << 24;
-            i_subpacket_len += *++p << 16;
-            i_subpacket_len += *++p << 8;
-            i_subpacket_len += *++p;
+            i_subpacket_len = U32_AT(p);
+            p += 4;
         }
 
         if( *p == ISSUER_SUBPACKET )
@@ -288,9 +277,9 @@ static size_t parse_signature_v4_packet( signature_packet_t *p_sig,
 
 
 static int parse_signature_packet( signature_packet_t *p_sig,
-                                   uint8_t *p_buf, size_t i_sig_len )
+                                   const uint8_t *p_buf, size_t i_packet_len )
 {
-    if( !i_sig_len ) /* 1st sanity check, we need at least the version */
+    if( !i_packet_len ) /* 1st sanity check, we need at least the version */
         return VLC_EGENERIC;
 
     p_sig->version = *p_buf++;
@@ -299,12 +288,12 @@ static int parse_signature_packet( signature_packet_t *p_sig,
     switch( p_sig->version )
     {
         case 3:
-            i_read = parse_signature_v3_packet( p_sig, p_buf, i_sig_len );
+            i_read = parse_signature_v3_packet( p_sig, p_buf, i_packet_len );
             break;
         case 4:
             p_sig->specific.v4.hashed_data = NULL;
             p_sig->specific.v4.unhashed_data = NULL;
-            i_read = parse_signature_v4_packet( p_sig, p_buf, i_sig_len );
+            i_read = parse_signature_v4_packet( p_sig, p_buf, i_packet_len );
             break;
         default:
             return VLC_EGENERIC;
@@ -313,10 +302,7 @@ static int parse_signature_packet( signature_packet_t *p_sig,
     if( i_read == 0 ) /* signature packet parsing has failed */
         goto error;
 
-    if( p_sig->public_key_algo != PUBLIC_KEY_ALGO_DSA )
-        goto error;
-
-    if( p_sig->digest_algo != DIGEST_ALGO_SHA1 )
+    if( p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA )
         goto error;
 
     switch( p_sig->type )
@@ -335,30 +321,16 @@ static int parse_signature_packet( signature_packet_t *p_sig,
     p_buf--; /* rewind to the version byte */
     p_buf += i_read;
 
-    if( i_read + 2 > i_sig_len )
+    if( p_sig->public_key_algo == GCRY_PK_DSA ) {
+        READ_MPI(p_sig->algo_specific.dsa.r, 256);
+        READ_MPI(p_sig->algo_specific.dsa.s, 256);
+    } else if ( p_sig->public_key_algo == GCRY_PK_RSA ) {
+        READ_MPI(p_sig->algo_specific.rsa.s, 4096);
+    } else
         goto error;
 
-    size_t i_r_len = mpi_len( p_buf ); i_read += 2;
-    if( i_read + i_r_len > i_sig_len || i_r_len > 20 )
-        goto error;
-
-    memcpy( p_sig->r, p_buf, 2 + i_r_len );
-    p_buf += 2 + i_r_len;
-    i_read += i_r_len;
-
-    if( i_read + 2 > i_sig_len )
-        goto error;
-
-    size_t i_s_len = mpi_len( p_buf ); i_read += 2;
-    if( i_read + i_s_len > i_sig_len || i_s_len > 20 )
-        goto error;
-
-    memcpy( p_sig->s, p_buf, 2 + i_s_len );
-    p_buf += 2 + i_s_len;
-    i_read += i_s_len;
-
-    assert( i_read == i_sig_len );
-    if( i_read < i_sig_len ) /* some extra data, hm ? */
+    assert( i_read == i_packet_len );
+    if( i_read < i_packet_len ) /* some extra data, hm ? */
         goto error;
 
     return VLC_SUCCESS;
@@ -404,10 +376,10 @@ static long crc_octets( uint8_t *octets, size_t len )
  * Transform an armored document in binary format
  * Used on public keys and signatures
  */
-static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
+static int pgp_unarmor( const char *p_ibuf, size_t i_ibuf_len,
                         uint8_t *p_obuf, size_t i_obuf_len )
 {
-    char *p_ipos = p_ibuf;
+    const char *p_ipos = p_ibuf;
     uint8_t *p_opos = p_obuf;
     int i_end = 0;
     int i_header_skipped = 0;
@@ -442,10 +414,7 @@ static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
         if( p_ipos[i_line_len - 1] == '=' )
         {
             i_end = 1;
-            p_ipos[i_line_len - 1] = '\0';
         }
-        else
-            p_ipos[i_line_len] = '\0';
 
         p_opos += vlc_b64_decode_binary_to_buffer(  p_opos,
                         p_obuf - p_opos + i_obuf_len, p_ipos );
@@ -466,14 +435,96 @@ static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
     return l_crc2 == l_crc ? p_opos - p_obuf : 0;
 }
 
+static int rsa_pkcs1_encode_sig(gcry_mpi_t *r_result, size_t size,
+                                const uint8_t *hash, int algo)
+{
+    uint8_t asn[100];
+    uint8_t frame[4096/8];
+
+    size_t asnlen = sizeof(asn);
+    size_t hashlen = gcry_md_get_algo_dlen(algo);
+
+    if (gcry_md_algo_info(algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+        return VLC_EGENERIC;
+
+    if (!hashlen || hashlen + asnlen + 4 > size)
+        return VLC_EGENERIC;
+
+    frame[0] = 0;
+    frame[1] = 1; /* block type */
+    int pad = size - hashlen - asnlen - 3 ;
+    memset (&frame[2], 0xff, pad );
+    frame[2+pad] = 0;
+    memcpy(&frame[3+pad], asn, asnlen);
+    memcpy(&frame[3+pad+asnlen], hash, hashlen);
+
+    if (gcry_mpi_scan(r_result, GCRYMPI_FMT_USG, frame, size, &size))
+        return VLC_EGENERIC;
+    return VLC_SUCCESS;
+}
 
 /*
- * Verify an OpenPGP signature made on some SHA-1 hash, with some DSA public key
+ * Verify an OpenPGP signature made with some RSA public key
  */
-int verify_signature( uint8_t *p_r, uint8_t *p_s, public_key_packet_t *p_key,
+static int verify_signature_rsa( signature_packet_t *sign, public_key_packet_t *p_key,
                       uint8_t *p_hash )
 {
-    /* the data to be verified (a SHA-1 hash) */
+    int ret = VLC_EGENERIC;
+    /* the data to be verified (a hash) */
+    const char *hash_sexp_s = "(data(flags raw)(value %m))";
+    /* the public key */
+    const char *key_sexp_s = "(public-key(rsa(n %m)(e %m)))";
+    /* the signature */
+    const char *sig_sexp_s = "(sig-val(rsa(s%m)))";
+
+    size_t erroff;
+    gcry_mpi_t n, e, s, hash;
+    n = e = s = hash = NULL;
+    gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
+    key_sexp = hash_sexp = sig_sexp = NULL;
+
+    int i_n_len = mpi_len( p_key->sig.rsa.n );
+    int i_e_len = mpi_len( p_key->sig.rsa.e );
+    if( gcry_mpi_scan( &n, GCRYMPI_FMT_USG, p_key->sig.rsa.n + 2, i_n_len, NULL ) ||
+        gcry_mpi_scan( &e, GCRYMPI_FMT_USG, p_key->sig.rsa.e + 2, i_e_len, NULL ) ||
+        gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, n, e ) )
+        goto out;
+
+    uint8_t *p_s = sign->algo_specific.rsa.s;
+    int i_s_len = mpi_len( p_s );
+    if( gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
+        gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, s ) )
+        goto out;
+
+    if( rsa_pkcs1_encode_sig (&hash, i_n_len, p_hash, sign->digest_algo) ||
+        gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
+        goto out;
+
+    if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
+        goto out;
+
+    ret = VLC_SUCCESS;
+
+out:
+    if( n ) gcry_mpi_release( n );
+    if( e ) gcry_mpi_release( e );
+    if( s ) gcry_mpi_release( s );
+    if( hash ) gcry_mpi_release( hash );
+    if( key_sexp ) gcry_sexp_release( key_sexp );
+    if( sig_sexp ) gcry_sexp_release( sig_sexp );
+    if( hash_sexp ) gcry_sexp_release( hash_sexp );
+    return ret;
+}
+
+/*
+ * Verify an OpenPGP signature made with some DSA public key
+ */
+static int verify_signature_dsa( signature_packet_t *sign, public_key_packet_t *p_key,
+                      uint8_t *p_hash )
+{
+    int ret = VLC_EGENERIC;
+
+    /* the data to be verified (a hash) */
     const char *hash_sexp_s = "(data(flags raw)(value %m))";
     /* the public key */
     const char *key_sexp_s = "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))";
@@ -486,35 +537,39 @@ int verify_signature( uint8_t *p_r, uint8_t *p_s, public_key_packet_t *p_key,
     gcry_sexp_t key_sexp, hash_sexp, sig_sexp;
     key_sexp = hash_sexp = sig_sexp = NULL;
 
-    int i_p_len = mpi_len( p_key->p );
-    int i_q_len = mpi_len( p_key->q );
-    int i_g_len = mpi_len( p_key->g );
-    int i_y_len = mpi_len( p_key->y );
-    if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->p + 2, i_p_len, NULL ) ||
-        gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->q + 2, i_q_len, NULL ) ||
-        gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->g + 2, i_g_len, NULL ) ||
-        gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->y + 2, i_y_len, NULL ) ||
+    int i_p_len = mpi_len( p_key->sig.dsa.p );
+    int i_q_len = mpi_len( p_key->sig.dsa.q );
+    int i_g_len = mpi_len( p_key->sig.dsa.g );
+    int i_y_len = mpi_len( p_key->sig.dsa.y );
+    if( gcry_mpi_scan( &p, GCRYMPI_FMT_USG, p_key->sig.dsa.p + 2, i_p_len, NULL ) ||
+        gcry_mpi_scan( &q, GCRYMPI_FMT_USG, p_key->sig.dsa.q + 2, i_q_len, NULL ) ||
+        gcry_mpi_scan( &g, GCRYMPI_FMT_USG, p_key->sig.dsa.g + 2, i_g_len, NULL ) ||
+        gcry_mpi_scan( &y, GCRYMPI_FMT_USG, p_key->sig.dsa.y + 2, i_y_len, NULL ) ||
         gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) )
-        goto problem;
+        goto out;
 
+    uint8_t *p_r = sign->algo_specific.dsa.r;
+    uint8_t *p_s = sign->algo_specific.dsa.s;
     int i_r_len = mpi_len( p_r );
     int i_s_len = mpi_len( p_s );
     if( gcry_mpi_scan( &r, GCRYMPI_FMT_USG, p_r + 2, i_r_len, NULL ) ||
         gcry_mpi_scan( &s, GCRYMPI_FMT_USG, p_s + 2, i_s_len, NULL ) ||
         gcry_sexp_build( &sig_sexp, &erroff, sig_sexp_s, r, s ) )
-        goto problem;
+        goto out;
 
-    int i_hash_len = 20;
+    int i_hash_len = gcry_md_get_algo_dlen (sign->digest_algo);
+    if (i_hash_len > i_q_len)
+        i_hash_len = i_q_len;
     if( gcry_mpi_scan( &hash, GCRYMPI_FMT_USG, p_hash, i_hash_len, NULL ) ||
         gcry_sexp_build( &hash_sexp, &erroff, hash_sexp_s, hash ) )
-        goto problem;
+        goto out;
 
     if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) )
-        goto problem;
+        goto out;
 
-    return VLC_SUCCESS;
+    ret = VLC_SUCCESS;
 
-problem:
+out:
     if( p ) gcry_mpi_release( p );
     if( q ) gcry_mpi_release( q );
     if( g ) gcry_mpi_release( g );
@@ -525,7 +580,22 @@ problem:
     if( key_sexp ) gcry_sexp_release( key_sexp );
     if( sig_sexp ) gcry_sexp_release( sig_sexp );
     if( hash_sexp ) gcry_sexp_release( hash_sexp );
-    return VLC_EGENERIC;
+
+    return ret;
+}
+
+/*
+ * Verify an OpenPGP signature made with some public key
+ */
+int verify_signature( signature_packet_t *sign, public_key_packet_t *p_key,
+                      uint8_t *p_hash )
+{
+    if (sign->public_key_algo == GCRY_PK_DSA)
+        return verify_signature_dsa(sign, p_key, p_hash);
+    else if (sign->public_key_algo == GCRY_PK_RSA)
+        return verify_signature_rsa(sign, p_key, p_hash);
+    else
+        return VLC_EGENERIC;
 }
 
 
@@ -538,8 +608,8 @@ problem:
 int parse_public_key( const uint8_t *p_key_data, size_t i_key_len,
                       public_key_t *p_key, const uint8_t *p_sig_issuer )
 {
-    uint8_t *pos = (uint8_t*) p_key_data;
-    uint8_t *max_pos = pos + i_key_len;
+    const uint8_t *pos = p_key_data;
+    const uint8_t *max_pos = pos + i_key_len;
 
     int i_status = 0;
 #define PUBLIC_KEY_FOUND    0x01
@@ -659,7 +729,7 @@ static int hash_from_binary_file( const char *psz_file, gcry_md_hd_t hd )
     uint8_t buffer[4096];
     size_t i_read;
 
-    FILE *f = utf8_fopen( psz_file, "r" );
+    FILE *f = vlc_fopen( psz_file, "r" );
     if( !f )
         return -1;
 
@@ -707,38 +777,42 @@ static uint8_t *hash_finish( gcry_md_hd_t hd, signature_packet_t *p_sig )
 
     gcry_md_final( hd );
 
-    uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, GCRY_MD_SHA1);
-    uint8_t *p_hash = malloc( 20 );
+    uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, p_sig->digest_algo) ;
+    unsigned int hash_len = gcry_md_get_algo_dlen (p_sig->digest_algo);
+    uint8_t *p_hash = malloc(hash_len);
     if( p_hash )
-        memcpy( p_hash, p_tmp, 20 );
+        memcpy(p_hash, p_tmp, hash_len);
     gcry_md_close( hd );
     return p_hash;
 }
 
 
 /*
- * return a sha1 hash of a text
+ * return a hash of a text
  */
-uint8_t *hash_sha1_from_text( const char *psz_string,
+uint8_t *hash_from_text( const char *psz_string,
         signature_packet_t *p_sig )
 {
     gcry_md_hd_t hd;
-    if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
+    if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
         return NULL;
 
     if( p_sig->type == TEXT_SIGNATURE )
     while( *psz_string )
     {
         size_t i_len = strcspn( psz_string, "\r\n" );
-        if( !i_len )
-            break;
 
-        gcry_md_write( hd, psz_string, i_len );
+        if( i_len )
+        {
+            gcry_md_write( hd, psz_string, i_len );
+            psz_string += i_len;
+        }
         gcry_md_putc( hd, '\r' );
         gcry_md_putc( hd, '\n' );
 
-        psz_string += i_len;
-        while( *psz_string == '\r' || *psz_string == '\n' )
+        if( *psz_string == '\r' )
+            psz_string++;
+        if( *psz_string == '\n' )
             psz_string++;
     }
     else
@@ -749,12 +823,12 @@ uint8_t *hash_sha1_from_text( const char *psz_string,
 
 
 /*
- * return a sha1 hash of a file
+ * return a hash of a file
  */
-uint8_t *hash_sha1_from_file( const char *psz_file, signature_packet_t *p_sig )
+uint8_t *hash_from_file( const char *psz_file, signature_packet_t *p_sig )
 {
     gcry_md_hd_t hd;
-    if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) )
+    if( gcry_md_open( &hd, p_sig->digest_algo, 0 ) )
         return NULL;
 
     if( hash_from_binary_file( psz_file, hd ) < 0 )
@@ -768,11 +842,16 @@ uint8_t *hash_sha1_from_file( const char *psz_file, signature_packet_t *p_sig )
 
 
 /*
- * Generate a SHA1 hash on a public key, to verify a signature made on that hash
+ * Generate a hash on a public key, to verify a signature made on that hash
  * Note that we need the signature (v4) to compute the hash
  */
-uint8_t *hash_sha1_from_public_key( public_key_t *p_pkey )
+uint8_t *hash_from_public_key( public_key_t *p_pkey )
 {
+    const uint8_t pk_algo = p_pkey->key.algo;
+    size_t i_size;
+    size_t i_p_len, i_g_len, i_q_len, i_y_len;
+    size_t i_n_len, i_e_len;
+
     if( p_pkey->sig.version != 4 )
         return NULL;
 
@@ -783,19 +862,27 @@ uint8_t *hash_sha1_from_public_key( public_key_t *p_pkey )
     gcry_error_t error = 0;
     gcry_md_hd_t hd;
 
-    error = gcry_md_open( &hd, GCRY_MD_SHA1, 0 );
+    if (pk_algo == GCRY_PK_DSA) {
+        i_p_len = mpi_len( p_pkey->key.sig.dsa.p );
+        i_g_len = mpi_len( p_pkey->key.sig.dsa.g );
+        i_q_len = mpi_len( p_pkey->key.sig.dsa.q );
+        i_y_len = mpi_len( p_pkey->key.sig.dsa.y );
+
+        i_size = 6 + 2*4 + i_p_len + i_g_len + i_q_len + i_y_len;
+    } else if (pk_algo == GCRY_PK_RSA) {
+        i_n_len = mpi_len( p_pkey->key.sig.rsa.n );
+        i_e_len = mpi_len( p_pkey->key.sig.rsa.e );
+
+        i_size = 6 + 2*2 + i_n_len + i_e_len;
+    } else
+        return NULL;
+
+    error = gcry_md_open( &hd, p_pkey->sig.digest_algo, 0 );
     if( error )
         return NULL;
 
     gcry_md_putc( hd, 0x99 );
 
-    size_t i_p_len = mpi_len( p_pkey->key.p );
-    size_t i_g_len = mpi_len( p_pkey->key.g );
-    size_t i_q_len = mpi_len( p_pkey->key.q );
-    size_t i_y_len = mpi_len( p_pkey->key.y );
-
-    size_t i_size = 6 + 2*4 + i_p_len + i_g_len + i_q_len + i_y_len;
-
     gcry_md_putc( hd, (i_size >> 8) & 0xff );
     gcry_md_putc( hd, i_size & 0xff );
 
@@ -803,17 +890,15 @@ uint8_t *hash_sha1_from_public_key( public_key_t *p_pkey )
     gcry_md_write( hd, p_pkey->key.timestamp, 4 );
     gcry_md_putc( hd, p_pkey->key.algo );
 
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.p, 2 );
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.p + 2, i_p_len );
-
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.q, 2 );
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.q + 2, i_q_len );
-
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.g, 2 );
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.g + 2, i_g_len );
-
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.y, 2 );
-    gcry_md_write( hd, (uint8_t*)&p_pkey->key.y + 2, i_y_len );
+    if (pk_algo == GCRY_PK_DSA) {
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.p, 2 + i_p_len );
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.q, 2 + i_q_len );
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.g, 2 + i_g_len );
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.dsa.y, 2 + i_y_len );
+    } else if (pk_algo == GCRY_PK_RSA) {
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.n, 2 + i_n_len );
+        gcry_md_write( hd, (uint8_t*)&p_pkey->key.sig.rsa.e, 2 + i_e_len );
+    }
 
     gcry_md_putc( hd, 0xb4 );
 
@@ -831,6 +916,7 @@ uint8_t *hash_sha1_from_public_key( public_key_t *p_pkey )
         p_hash[0] != p_pkey->sig.hash_verification[0] ||
         p_hash[1] != p_pkey->sig.hash_verification[1] )
     {
+        free(p_hash);
         return NULL;
     }
 
@@ -971,8 +1057,8 @@ int download_signature( vlc_object_t *p_this, signature_packet_t *p_sig,
 
     if( packet_type( *p_buf ) != SIGNATURE_PACKET )
     {
-        free( p_buf );
         msg_Dbg( p_this, "Not a signature: %d", *p_buf );
+        free( p_buf );
         return VLC_EGENERIC;
     }