📄 update.c
字号:
free( psz_url ); if( !p_stream ) return NULL; int64_t i_size = stream_Size( p_stream ); if( i_size < 0 ) { stream_Delete( p_stream ); return NULL; } uint8_t *p_buf = (uint8_t*)malloc( i_size ); if( !p_buf ) { stream_Delete( p_stream ); return NULL; } 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 read full GPG key" ); free( p_buf ); return NULL; } public_key_t *p_pkey = (public_key_t*) malloc( sizeof( public_key_t ) ); if( !p_pkey ) { free( p_buf ); return NULL; } memcpy( p_pkey->longid, p_longid, 8 ); int i_error = parse_public_key( p_buf, i_read, p_pkey, p_signature_issuer ); free( p_buf ); if( i_error != VLC_SUCCESS ) { msg_Dbg( p_this, "Couldn't parse GPG key" ); free( p_pkey ); return NULL; } return p_pkey;}/* * Generate a SHA1 hash on a public key, to verify a signature made on that hash * Note that we need the signature (v4) to compute the hash */static uint8_t *key_sign_hash( public_key_t *p_pkey ){ if( p_pkey->sig.version != 4 ) return NULL; if( p_pkey->sig.type < GENERIC_KEY_SIGNATURE || p_pkey->sig.type > POSITIVE_KEY_SIGNATURE ) return NULL; gcry_error_t error = 0; gcry_md_hd_t hd; error = gcry_md_open( &hd, GCRY_MD_SHA1, 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 ); gcry_md_putc( hd, p_pkey->key.version ); 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 ); gcry_md_putc( hd, 0xb4 ); size_t i_len = strlen((char*)p_pkey->psz_username); gcry_md_putc( hd, (i_len << 24) & 0xff ); gcry_md_putc( hd, (i_len << 16) & 0xff ); gcry_md_putc( hd, (i_len << 8) & 0xff ); gcry_md_putc( hd, (i_len) & 0xff ); gcry_md_write( hd, p_pkey->psz_username, i_len ); size_t i_hashed_data_len = scalar_number( p_pkey->sig.specific.v4.hashed_data_len, 2 ); gcry_md_putc( hd, p_pkey->sig.version ); gcry_md_putc( hd, p_pkey->sig.type ); gcry_md_putc( hd, p_pkey->sig.public_key_algo ); gcry_md_putc( hd, p_pkey->sig.digest_algo ); gcry_md_write( hd, p_pkey->sig.specific.v4.hashed_data_len, 2 ); gcry_md_write( hd, p_pkey->sig.specific.v4.hashed_data, i_hashed_data_len ); gcry_md_putc( hd, 0x04 ); gcry_md_putc( hd, 0xff ); i_hashed_data_len += 6; /* hashed data + 6 bytes header */ gcry_md_putc( hd, (i_hashed_data_len << 24) & 0xff); gcry_md_putc( hd, (i_hashed_data_len << 16) &0xff ); gcry_md_putc( hd, (i_hashed_data_len << 8) & 0xff ); gcry_md_putc( hd, (i_hashed_data_len) & 0xff ); gcry_md_final( hd ); uint8_t *p_tmp = gcry_md_read( hd, GCRY_MD_SHA1); if( !p_tmp || p_tmp[0] != p_pkey->sig.hash_verification[0] || p_tmp[1] != p_pkey->sig.hash_verification[1] ) { gcry_md_close( hd ); return NULL; } uint8_t *p_hash = malloc( 20 ); if( p_hash ) memcpy( p_hash, p_tmp, 20 ); gcry_md_close( hd ); return p_hash;}/***************************************************************************** * Update_t functions *****************************************************************************//** * Create a new update VLC struct * * \param p_this the calling vlc_object * \return pointer to new update_t or NULL */update_t *__update_New( vlc_object_t *p_this ){ update_t *p_update; assert( p_this ); p_update = (update_t *)malloc( sizeof( update_t ) ); if( !p_update ) return NULL; vlc_mutex_init( &p_update->lock ); p_update->p_libvlc = p_this->p_libvlc; p_update->release.psz_url = NULL; p_update->release.psz_desc = NULL; p_update->p_download = NULL; p_update->p_check = NULL; p_update->p_pkey = NULL; vlc_gcrypt_init(); return p_update;}/** * Delete an update_t struct * * \param p_update update_t* pointer * \return nothing */void update_Delete( update_t *p_update ){ assert( p_update ); if( p_update->p_check ) { assert( !p_update->p_download ); vlc_object_kill( p_update->p_check ); vlc_thread_join( p_update->p_check ); } else if( p_update->p_download ) { vlc_object_kill( p_update->p_download ); vlc_thread_join( p_update->p_download ); vlc_object_release( p_update->p_download ); } vlc_mutex_destroy( &p_update->lock ); free( p_update->release.psz_url ); free( p_update->release.psz_desc ); free( p_update->p_pkey ); free( p_update );}/** * Empty the release struct * * \param p_update update_t* pointer * \return nothing */static void EmptyRelease( update_t *p_update ){ p_update->release.i_major = 0; p_update->release.i_minor = 0; p_update->release.i_revision = 0; FREENULL( p_update->release.psz_url ); FREENULL( p_update->release.psz_desc );}/** * Get the update file and parse it * p_update has to be locked when calling this function * * \param p_update pointer to update struct * \return true if the update is valid and authenticated */static bool GetUpdateFile( update_t *p_update ){ stream_t *p_stream = NULL; int i_major = 0; int i_minor = 0; int i_revision = 0; unsigned char extra; char *psz_version_line = NULL; p_stream = stream_UrlNew( p_update->p_libvlc, UPDATE_VLC_STATUS_URL ); if( !p_stream ) { msg_Err( p_update->p_libvlc, "Failed to open %s for reading", UPDATE_VLC_STATUS_URL ); goto error; } /* Start reading the status file */ if( !( psz_version_line = stream_ReadLine( p_stream ) ) ) { msg_Err( p_update->p_libvlc, "Update file %s is corrupted : missing version", UPDATE_VLC_STATUS_URL ); goto error; } /* first line : version number */ p_update->release.extra = 0; switch( sscanf( psz_version_line, "%i.%i.%i%c", &i_major, &i_minor, &i_revision, &extra ) ) { case 4: p_update->release.extra = extra; case 3: p_update->release.i_major = i_major; p_update->release.i_minor = i_minor; p_update->release.i_revision = i_revision; break; default: msg_Err( p_update->p_libvlc, "Update version false formated" ); goto error; } /* second line : URL */ if( !( p_update->release.psz_url = stream_ReadLine( p_stream ) ) ) { msg_Err( p_update->p_libvlc, "Update file %s is corrupted : URL missing", UPDATE_VLC_STATUS_URL ); goto error; } /* Remaining data : description */ int i_read = stream_Size( p_stream ) - stream_Tell( p_stream ); if( i_read <= 0 ) { msg_Err( p_update->p_libvlc, "Update file %s is corrupted: description missing", UPDATE_VLC_STATUS_URL ); goto error; } p_update->release.psz_desc = (char*) malloc( i_read + 1 ); if( !p_update->release.psz_desc ) goto error; if( stream_Read( p_stream, p_update->release.psz_desc, i_read ) != i_read ) { msg_Err( p_update->p_libvlc, "Couldn't download update file %s", UPDATE_VLC_STATUS_URL ); goto error; } p_update->release.psz_desc[i_read] = '\0'; stream_Delete( p_stream ); p_stream = NULL; /* Now that we know the status is valid, we must download its signature * to authenticate it */ signature_packet_t sign; if( download_signature( VLC_OBJECT( p_update->p_libvlc ), &sign, UPDATE_VLC_STATUS_URL ) != VLC_SUCCESS ) { msg_Err( p_update->p_libvlc, "Couldn't download signature of status file" ); goto error; } if( sign.type != BINARY_SIGNATURE && sign.type != TEXT_SIGNATURE ) { msg_Err( p_update->p_libvlc, "Invalid signature type" ); goto error; } p_update->p_pkey = (public_key_t*)malloc( sizeof( public_key_t ) ); if( !p_update->p_pkey ) goto error; if( parse_public_key( videolan_public_key, sizeof( videolan_public_key ), p_update->p_pkey, NULL ) != VLC_SUCCESS ) { msg_Err( p_update->p_libvlc, "Couldn't parse embedded public key, something went really wrong..." ); FREENULL( p_update->p_pkey ); goto error; } memcpy( p_update->p_pkey->longid, videolan_public_key_longid, 8 ); if( memcmp( sign.issuer_longid, p_update->p_pkey->longid , 8 ) != 0 ) { msg_Dbg( p_update->p_libvlc, "Need to download the GPG key" ); public_key_t *p_new_pkey = download_key( VLC_OBJECT(p_update->p_libvlc), sign.issuer_longid, videolan_public_key_longid ); if( !p_new_pkey ) { msg_Err( p_update->p_libvlc, "Couldn't download GPG key" ); FREENULL( p_update->p_pkey ); goto error; } uint8_t *p_hash = key_sign_hash( p_new_pkey ); if( !p_hash ) { msg_Err( p_update->p_libvlc, "Failed to hash signature" ); free( p_new_pkey ); FREENULL( p_update->p_pkey ); goto error; } if( verify_signature( p_new_pkey->sig.r, p_new_pkey->sig.s, &p_update->p_pkey->key, p_hash ) == VLC_SUCCESS ) { free( p_hash ); msg_Info( p_update->p_libvlc, "Key authenticated" ); free( p_update->p_pkey ); p_update->p_pkey = p_new_pkey; } else { free( p_hash ); msg_Err( p_update->p_libvlc, "Key signature invalid !\n" ); goto error; } } gcry_md_hd_t hd; if( gcry_md_open( &hd, GCRY_MD_SHA1, 0 ) ) goto error_hd; gcry_md_write( hd, psz_version_line, strlen( psz_version_line ) ); FREENULL( psz_version_line ); if( sign.type == TEXT_SIGNATURE ) gcry_md_putc( hd, '\r' ); gcry_md_putc( hd, '\n' ); gcry_md_write( hd, p_update->release.psz_url, strlen( p_update->release.psz_url ) ); if( sign.type == TEXT_SIGNATURE ) gcry_md_putc( hd, '\r' ); gcry_md_putc( hd, '\n' ); char *psz_desc = p_update->release.psz_desc; while( *psz_desc ) { size_t i_len = strcspn( psz_desc, "\r\n" ); if( !i_len ) break; gcry_md_write( hd, psz_desc, i_len ); if( sign.type == TEXT_SIGNATURE ) gcry_md_putc( hd, '\r' ); gcry_md_putc( hd, '\n' ); psz_desc += i_len; while( *psz_desc == '\r' || *psz_desc == '\n' ) psz_desc++; } if( sign.version == 3 ) { gcry_md_putc( hd, sign.type ); gcry_md_write( hd, &sign.specific.v3.timestamp, 4 ); } else if( sign.version == 4 ) { gcry_md_putc( hd, sign.version ); gcry_md_putc( hd, sign.type ); gcry_md_putc( hd, sign.public_key_algo ); gcry_md_putc( hd, sign.digest_algo ); gcry_md_write( hd, sign.specific.v4.hashed_data_len, 2 ); size_t i_len = scalar_number( sign.specific.v4.hashed_data_len, 2 ); gcry_md_write( hd, sign.specific.v4.hashed_data, i_len ); gcry_md_putc( hd, 0x04 ); gcry_md_putc( hd, 0xFF ); i_len += 6; /* hashed data + 6 bytes header */ gcry_md_putc( hd, (i_len << 24) & 0xff); gcry_md_putc( hd, (i_len << 16) &0xff ); gcry_md_putc( hd, (i_len << 8) & 0xff ); gcry_md_putc( hd, (i_len) & 0xff ); } else { /* RFC 4880 only tells about versions 3 and 4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -