📄 update.c
字号:
} return crc & 0xFFFFFFL;}/* * 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, uint8_t *p_obuf, size_t i_obuf_len ){ char *p_ipos = p_ibuf; uint8_t *p_opos = p_obuf; int i_end = 0; int i_header_skipped = 0; while( !i_end && p_ipos < p_ibuf + i_ibuf_len && *p_ipos != '=' ) { if( *p_ipos == '\r' || *p_ipos == '\n' ) { p_ipos++; continue; } size_t i_line_len = strcspn( p_ipos, "\r\n" ); if( i_line_len == 0 ) continue; if( !i_header_skipped ) { if( !strncmp( p_ipos, "-----BEGIN PGP", 14 ) ) i_header_skipped = 1; p_ipos += i_line_len + 1; continue; } if( !strncmp( p_ipos, "Version:", 8 ) ) { p_ipos += i_line_len + 1; continue; } 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 ); p_ipos += i_line_len + 1; } /* XXX: the CRC is OPTIONAL, really require it ? */ if( p_ipos + 5 > p_ibuf + i_ibuf_len || *p_ipos++ != '=' ) return 0; uint8_t p_crc[3]; if( vlc_b64_decode_binary_to_buffer( p_crc, 3, p_ipos ) != 3 ) return 0; long l_crc = crc_octets( p_obuf, p_opos - p_obuf ); long l_crc2 = ( 0 << 24 ) + ( p_crc[0] << 16 ) + ( p_crc[1] << 8 ) + p_crc[2]; return l_crc2 == l_crc ? p_opos - p_obuf : 0;}/* * Download the signature associated to a document or a binary file. * We're given the file's url, we just append ".asc" to it and download */static int download_signature( vlc_object_t *p_this, signature_packet_t *p_sig, const char *psz_url ){ char *psz_sig = (char*) malloc( strlen( psz_url ) + 4 + 1 ); /* ".asc" + \0 */ if( !psz_sig ) return VLC_ENOMEM; strcpy( psz_sig, psz_url ); strcat( psz_sig, ".asc" ); stream_t *p_stream = stream_UrlNew( p_this, psz_sig ); free( psz_sig ); if( !p_stream ) return VLC_ENOMEM; int64_t i_size = stream_Size( p_stream ); msg_Dbg( p_this, "Downloading signature (%"PRId64" bytes)", i_size ); uint8_t *p_buf = (uint8_t*)malloc( i_size ); if( !p_buf ) { stream_Delete( p_stream ); return VLC_ENOMEM; } int i_read = stream_Read( p_stream, p_buf, (int)i_size ); stream_Delete( p_stream ); if( i_read != (int)i_size ) { msg_Dbg( p_this, "Couldn't download full signature (only %d bytes)", i_read ); free( p_buf ); return VLC_EGENERIC; } if( (uint8_t)*p_buf < 0x80 ) /* ASCII */ { msg_Dbg( p_this, "Unarmoring signature" ); uint8_t* p_unarmored = (uint8_t*) malloc( ( i_size * 3 ) / 4 + 1 ); if( !p_unarmored ) { free( p_buf ); return VLC_EGENERIC; } int i_bytes = pgp_unarmor( (char*)p_buf, i_size, p_unarmored, i_size ); free( p_buf ); p_buf = p_unarmored; i_size = i_bytes; if( i_bytes < 2 ) { free( p_buf ); msg_Dbg( p_this, "Unarmoring failed : corrupted signature ?" ); return VLC_EGENERIC; } } if( packet_type( *p_buf ) != SIGNATURE_PACKET ) { free( p_buf ); msg_Dbg( p_this, "Not a signature: %d", *p_buf ); return VLC_EGENERIC; } size_t i_header_len = packet_header_len( *p_buf ); if( ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) || i_header_len + 1 > (size_t)i_size ) { free( p_buf ); msg_Dbg( p_this, "Invalid signature packet header" ); return VLC_EGENERIC; } size_t i_len = scalar_number( p_buf+1, i_header_len ); if( i_len + i_header_len + 1 != (size_t)i_size ) { free( p_buf ); msg_Dbg( p_this, "Invalid signature packet" ); return VLC_EGENERIC; } int i_ret = parse_signature_packet( p_sig, p_buf+1+i_header_len, i_len ); free( p_buf ); if( i_ret != VLC_SUCCESS ) { msg_Dbg( p_this, "Couldn't parse signature" ); return i_ret; } if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE ) { msg_Dbg( p_this, "Invalid signature type: %d", p_sig->type ); if( p_sig->version == 4 ) { free( p_sig->specific.v4.hashed_data ); free( p_sig->specific.v4.unhashed_data ); } return VLC_EGENERIC; } return VLC_SUCCESS;}/* * Verify an OpenPGP signature made on some SHA-1 hash, with some DSA public key */static int verify_signature( uint8_t *p_r, uint8_t *p_s, public_key_packet_t *p_key, uint8_t *p_hash ){ /* the data to be verified (a SHA-1 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)))"; /* the signature */ const char *sig_sexp_s = "(sig-val(dsa(r %m )(s %m )))"; size_t erroff; gcry_mpi_t p, q, g, y, r, s, hash; p = q = g = y = r = s = hash = NULL; 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 ) || gcry_sexp_build( &key_sexp, &erroff, key_sexp_s, p, q, g, y ) ) goto problem; 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; int i_hash_len = 20; 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; if( gcry_pk_verify( sig_sexp, hash_sexp, key_sexp ) ) goto problem; return VLC_SUCCESS;problem: if( p ) gcry_mpi_release( p ); if( q ) gcry_mpi_release( q ); if( g ) gcry_mpi_release( g ); if( y ) gcry_mpi_release( y ); if( r ) gcry_mpi_release( r ); 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 VLC_EGENERIC;}/* * fill a public_key_t with public key data, including: * * public key packet * * signature packet issued by key which long id is p_sig_issuer * * user id packet */static int parse_public_key( const uint8_t *p_key_data, size_t i_key_len, public_key_t *p_key, const uint8_t *p_sig_issuer ){ uint8_t *pos = (uint8_t*) p_key_data; uint8_t *max_pos = pos + i_key_len; int i_status = 0;#define PUBLIC_KEY_FOUND 0x01#define USER_ID_FOUND 0x02#define SIGNATURE_FOUND 0X04 uint8_t *p_key_unarmored = NULL; p_key->psz_username = NULL; p_key->sig.specific.v4.hashed_data = NULL; p_key->sig.specific.v4.unhashed_data = NULL; if( !( *pos & 0x80 ) ) { /* first byte is ASCII, unarmoring */ p_key_unarmored = (uint8_t*)malloc( i_key_len ); if( !p_key_unarmored ) return VLC_ENOMEM; int i_len = pgp_unarmor( (char*)p_key_data, i_key_len, p_key_unarmored, i_key_len ); if( i_len == 0 ) goto error; pos = p_key_unarmored; max_pos = pos + i_len; } while( pos < max_pos ) { if( !(*pos & 0x80) || *pos & 0x40 ) goto error; int i_type = packet_type( *pos ); int i_header_len = packet_header_len( *pos++ ); if( pos + i_header_len > max_pos || ( i_header_len != 1 && i_header_len != 2 && i_header_len != 4 ) ) goto error; int i_packet_len = scalar_number( pos, i_header_len ); pos += i_header_len; if( pos + i_packet_len > max_pos ) goto error; switch( i_type ) { case PUBLIC_KEY_PACKET: i_status |= PUBLIC_KEY_FOUND; if( parse_public_key_packet( &p_key->key, pos, i_packet_len ) != VLC_SUCCESS ) goto error; break; case SIGNATURE_PACKET: /* we accept only v4 signatures here */ if( i_status & SIGNATURE_FOUND || !p_sig_issuer ) break; int i_ret = parse_signature_packet( &p_key->sig, pos, i_packet_len ); if( i_ret == VLC_SUCCESS ) { if( p_key->sig.version != 4 ) break; if( memcmp( p_key->sig.issuer_longid, p_sig_issuer, 8 ) ) { free( p_key->sig.specific.v4.hashed_data ); free( p_key->sig.specific.v4.unhashed_data ); p_key->sig.specific.v4.hashed_data = NULL; p_key->sig.specific.v4.unhashed_data = NULL; break; } i_status |= SIGNATURE_FOUND; } break; case USER_ID_PACKET: if( p_key->psz_username ) /* save only the first User ID */ break; i_status |= USER_ID_FOUND; p_key->psz_username = (uint8_t*)malloc( i_packet_len + 1); if( !p_key->psz_username ) goto error; memcpy( p_key->psz_username, pos, i_packet_len ); p_key->psz_username[i_packet_len] = '\0'; break; default: break; } pos += i_packet_len; } free( p_key_unarmored ); if( !( i_status & ( PUBLIC_KEY_FOUND | USER_ID_FOUND ) ) ) return VLC_EGENERIC; if( p_sig_issuer && !( i_status & SIGNATURE_FOUND ) ) return VLC_EGENERIC; return VLC_SUCCESS;error: if( p_key->sig.version == 4 ) { free( p_key->sig.specific.v4.hashed_data ); free( p_key->sig.specific.v4.unhashed_data ); } free( p_key->psz_username ); free( p_key_unarmored ); return VLC_EGENERIC;}/* * return a sha1 hash of a file */static uint8_t *hash_sha1_from_file( const char *psz_file, signature_packet_t *p_sig ){ if( p_sig->type != BINARY_SIGNATURE && p_sig->type != TEXT_SIGNATURE ) return NULL; FILE *f = utf8_fopen( psz_file, "r" ); if( !f ) return NULL; uint8_t buffer[4096]; gcry_md_hd_t hd; if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) ) { fclose( f ); return NULL; } size_t i_read; while( ( i_read = fread( buffer, 1, sizeof(buffer), f ) ) > 0 ) gcry_md_write( hd, buffer, i_read ); if( p_sig->version == 3 ) { gcry_md_putc( hd, p_sig->type ); gcry_md_write( hd, &p_sig->specific.v3.timestamp, 4 ); } else if( p_sig->version == 4 ) { gcry_md_putc( hd, p_sig->version ); gcry_md_putc( hd, p_sig->type ); gcry_md_putc( hd, p_sig->public_key_algo ); gcry_md_putc( hd, p_sig->digest_algo ); gcry_md_write( hd, p_sig->specific.v4.hashed_data_len, 2 ); size_t i_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 ); gcry_md_write( hd, p_sig->specific.v4.hashed_data, i_len ); } else { /* RFC 4880 only tells about versions 3 and 4 */ gcry_md_close( hd ); return NULL; } fclose( f ); gcry_md_final( hd ); uint8_t *p_tmp = (uint8_t*) gcry_md_read( hd, GCRY_MD_SHA1); uint8_t *p_hash = malloc( 20 ); if( p_hash ) memcpy( p_hash, p_tmp, 20 ); gcry_md_close( hd ); return p_hash;}/* * download a public key (the last one) from videolan server, and parse it */static public_key_t *download_key( vlc_object_t *p_this, const uint8_t *p_longid, const uint8_t *p_signature_issuer ){ char *psz_url; if( asprintf( &psz_url, "http://download.videolan.org/pub/keys/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X.asc", p_longid[0], p_longid[1], p_longid[2], p_longid[3], p_longid[4], p_longid[5], p_longid[6], p_longid[7] ) == -1 ) return NULL; stream_t *p_stream = stream_UrlNew( p_this, psz_url );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -