Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-2-2
Commits
9d7bb46d
Commit
9d7bb46d
authored
Dec 31, 2007
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update: use PGP to authenticate status file and downloaded binaries
parent
d25a2799
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
197 additions
and
74 deletions
+197
-74
include/vlc_update.h
include/vlc_update.h
+1
-49
src/misc/update.c
src/misc/update.c
+196
-25
No files found.
include/vlc_update.h
View file @
9d7bb46d
...
...
@@ -156,59 +156,11 @@ struct public_key_t
typedef
struct
public_key_t
public_key_t
;
/* We trust this public key, and by extension, also keys signed by it. */
//#define OLD 1 //Define OLD to use Videolan Key 2006, to test public key download
static
uint8_t
videolan_public_key_longid
[
8
]
=
{
#ifdef OLD
0xC3
,
0x67
,
0xD8
,
0xB9
,
0x81
,
0xCA
,
0xCA
,
0x84
#else
0x90
,
0x28
,
0x17
,
0xE4
,
0xAA
,
0x5F
,
0x4D
,
0xE6
#endif
};
static
uint8_t
videolan_public_key
[]
=
{
#ifdef OLD
"-----BEGIN PGP PUBLIC KEY BLOCK-----
\n
"
"Version: GnuPG v2.0.4 (FreeBSD)
\n
"
"
\n
"
"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
\n
"
"=tVe2
\n
"
"-----END PGP PUBLIC KEY BLOCK-----
\n
"
#else
"-----BEGIN PGP PUBLIC KEY BLOCK-----
\n
"
"Version: GnuPG v2.0.4 (FreeBSD)
\n
"
"
\n
"
...
...
@@ -243,7 +195,6 @@ static uint8_t videolan_public_key[] = {
"oMPb2o2D9gSwQFKXhamx2YdrykHOAKDqQ1tHH3ULY5cLLAKVaQtsNhVEtQ==
\n
"
"=qrc1
\n
"
"-----END PGP PUBLIC KEY BLOCK-----
\n
"
#endif
};
enum
...
...
@@ -274,6 +225,7 @@ struct update_t
libvlc_int_t
*
p_libvlc
;
vlc_mutex_t
lock
;
struct
update_release_t
release
;
///< Release (version)
public_key_t
*
p_pkey
;
};
#define update_New( a ) __update_New( VLC_OBJECT( a ) )
...
...
src/misc/update.c
View file @
9d7bb46d
...
...
@@ -28,8 +28,6 @@
* This file contains functions related to VLC and plugins update management
*/
/* TODO: pgp verification of the status file, and downloaded binaries */
/*****************************************************************************
* Preamble
*****************************************************************************/
...
...
@@ -44,6 +42,8 @@
#include <vlc_stream.h>
#include <vlc_interface.h>
#include <unistd.h>
/* unlink() */
/*****************************************************************************
* Misc defines
*****************************************************************************/
...
...
@@ -81,7 +81,7 @@
* Local Prototypes
*****************************************************************************/
static
void
EmptyRelease
(
update_t
*
p_update
);
static
v
oid
GetUpdateFile
(
update_t
*
p_update
);
static
v
lc_bool_t
GetUpdateFile
(
update_t
*
p_update
);
static
int
CompareReleases
(
const
struct
update_release_t
*
p1
,
const
struct
update_release_t
*
p2
);
static
char
*
size_str
(
long
int
l_size
);
...
...
@@ -330,7 +330,8 @@ static int pgp_unarmor( char *p_ibuf, size_t i_ibuf_len,
* 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_v3_t
*
p_sig
,
char
*
psz_url
)
signature_packet_v3_t
*
p_sig
,
const
char
*
psz_url
)
{
char
*
psz_sig
=
(
char
*
)
malloc
(
strlen
(
psz_url
)
+
4
+
1
);
/* ".asc" + \0 */
if
(
!
psz_sig
)
...
...
@@ -593,7 +594,7 @@ static uint8_t *hash_sha1_from_file( const char *psz_file,
if
(
!
f
)
return
NULL
;
uint8_t
buffer
[
4096
];
//FIXME
uint8_t
buffer
[
4096
];
gcry_md_hd_t
hd
;
if
(
gcry_md_open
(
&
hd
,
GCRY_MD_SHA1
,
0
)
)
...
...
@@ -621,11 +622,9 @@ static uint8_t *hash_sha1_from_file( const char *psz_file,
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
)
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
);
...
...
@@ -765,6 +764,8 @@ update_t *__update_New( vlc_object_t *p_this )
p_update
->
release
.
psz_url
=
NULL
;
p_update
->
release
.
psz_desc
=
NULL
;
p_update
->
p_pkey
=
NULL
;
return
p_update
;
}
...
...
@@ -780,8 +781,9 @@ void update_Delete( update_t *p_update )
vlc_mutex_destroy
(
&
p_update
->
lock
);
FREENULL
(
p_update
->
release
.
psz_url
);
FREENULL
(
p_update
->
release
.
psz_desc
);
free
(
p_update
->
release
.
psz_url
);
free
(
p_update
->
release
.
psz_desc
);
free
(
p_update
->
p_pkey
);
free
(
p_update
);
}
...
...
@@ -807,9 +809,9 @@ static void EmptyRelease( update_t *p_update )
* *p_update has to be locked when calling this function
*
* \param p_update pointer to update struct
* \return
nothing
* \return
VLC_TRUE if the update is valid and authenticated
*/
static
v
oid
GetUpdateFile
(
update_t
*
p_update
)
static
v
lc_bool_t
GetUpdateFile
(
update_t
*
p_update
)
{
stream_t
*
p_stream
=
NULL
;
int
i_major
=
0
;
...
...
@@ -817,6 +819,7 @@ static void GetUpdateFile( update_t *p_update )
int
i_revision
=
0
;
unsigned
char
extra
;
char
*
psz_line
=
NULL
;
char
*
psz_version_line
=
NULL
;
p_stream
=
stream_UrlNew
(
p_update
->
p_libvlc
,
UPDATE_VLC_STATUS_URL
);
if
(
!
p_stream
)
...
...
@@ -834,6 +837,7 @@ static void GetUpdateFile( update_t *p_update )
goto
error
;
}
psz_version_line
=
psz_line
;
/* first line : version number */
p_update
->
release
.
extra
=
0
;
switch
(
sscanf
(
psz_line
,
"%i.%i.%i%c"
,
&
i_major
,
&
i_minor
,
&
i_revision
,
&
extra
)
)
...
...
@@ -847,7 +851,6 @@ static void GetUpdateFile( update_t *p_update )
break
;
default:
msg_Err
(
p_update
->
p_libvlc
,
"Update version false formated"
);
free
(
psz_line
);
goto
error
;
}
...
...
@@ -870,9 +873,130 @@ static void GetUpdateFile( update_t *p_update )
}
p_update
->
release
.
psz_desc
=
psz_line
;
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_v3_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
;
}
if
(
memcmp
(
sign
.
issuer_longid
,
videolan_public_key_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
(
VLC_OBJECT
(
p_update
->
p_libvlc
),
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
;
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'
);
gcry_md_write
(
hd
,
p_update
->
release
.
psz_desc
,
strlen
(
p_update
->
release
.
psz_desc
)
);
if
(
sign
.
type
==
TEXT_SIGNATURE
)
gcry_md_putc
(
hd
,
'\r'
);
gcry_md_putc
(
hd
,
'\n'
);
gcry_md_putc
(
hd
,
sign
.
type
);
gcry_md_write
(
hd
,
&
sign
.
timestamp
,
4
);
gcry_md_final
(
hd
);
uint8_t
*
p_hash
=
gcry_md_read
(
hd
,
GCRY_MD_SHA1
);
if
(
p_hash
[
0
]
!=
sign
.
hash_verification
[
0
]
||
p_hash
[
1
]
!=
sign
.
hash_verification
[
1
]
)
{
msg_Warn
(
p_update
->
p_libvlc
,
"Bad SHA1 hash for status file"
);
free
(
p_hash
);
goto
error
;
}
if
(
verify_signature
(
VLC_OBJECT
(
p_update
->
p_libvlc
),
sign
.
r
,
sign
.
s
,
&
p_update
->
p_pkey
->
key
,
p_hash
)
!=
VLC_SUCCESS
)
{
msg_Err
(
p_update
->
p_libvlc
,
"BAD SIGNATURE for status file"
);
free
(
p_hash
);
goto
error
;
}
else
{
msg_Info
(
p_update
->
p_libvlc
,
"Status file authenticated"
);
free
(
p_hash
);
return
VLC_TRUE
;
}
error:
if
(
p_stream
)
stream_Delete
(
p_stream
);
free
(
psz_version_line
);
return
VLC_FALSE
;
}
...
...
@@ -913,14 +1037,15 @@ void update_Check( update_t *p_update, void (*pf_callback)( void* ), void *p_dat
void
update_CheckReal
(
update_check_thread_t
*
p_uct
)
{
vlc_bool_t
b_ret
;
vlc_mutex_lock
(
&
p_uct
->
p_update
->
lock
);
EmptyRelease
(
p_uct
->
p_update
);
GetUpdateFile
(
p_uct
->
p_update
);
b_ret
=
GetUpdateFile
(
p_uct
->
p_update
);
vlc_mutex_unlock
(
&
p_uct
->
p_update
->
lock
);
if
(
p_uct
->
pf_callback
)
/* FIXME: return b_ret in pf_callback */
if
(
b_ret
&&
p_uct
->
pf_callback
)
(
p_uct
->
pf_callback
)(
p_uct
->
p_data
);
vlc_object_destroy
(
p_uct
);
...
...
@@ -1049,7 +1174,7 @@ void update_DownloadReal( update_download_thread_t *p_udt )
if
(
!
p_stream
)
{
msg_Err
(
p_udt
,
"Failed to open %s for reading"
,
p_update
->
release
.
psz_url
);
goto
e
rror
;
goto
e
nd
;
}
/* Get the stream size */
...
...
@@ -1060,23 +1185,23 @@ void update_DownloadReal( update_download_thread_t *p_udt )
if
(
!
psz_tmpdestfile
)
{
msg_Err
(
p_udt
,
"The URL %s is false formated"
,
p_update
->
release
.
psz_url
);
goto
e
rror
;
goto
e
nd
;
}
psz_tmpdestfile
++
;
if
(
asprintf
(
&
psz_destfile
,
"%s%s"
,
psz_destdir
,
psz_tmpdestfile
)
==
-
1
)
goto
e
rror
;
goto
e
nd
;
p_file
=
utf8_fopen
(
psz_destfile
,
"w"
);
if
(
!
p_file
)
{
msg_Err
(
p_udt
,
"Failed to open %s for writing"
,
psz_destfile
);
goto
e
rror
;
goto
e
nd
;
}
/* Create a buffer and fill it with the downloaded file */
p_buffer
=
(
void
*
)
malloc
(
1
<<
10
);
if
(
!
p_buffer
)
goto
e
rror
;
goto
e
nd
;
psz_size
=
size_str
(
l_size
);
if
(
asprintf
(
&
psz_status
,
"%s
\n
Downloading... O.O/%s %.1f%% done"
,
p_update
->
release
.
psz_url
,
psz_size
,
0
.
0
)
!=
-
1
)
...
...
@@ -1106,6 +1231,7 @@ void update_DownloadReal( update_download_thread_t *p_udt )
/* Finish the progress bar or delete the file if the user had canceled */
fclose
(
p_file
);
p_file
=
NULL
;
if
(
!
intf_ProgressIsCancelled
(
p_udt
,
i_progress
)
)
{
if
(
asprintf
(
&
psz_status
,
"%s
\n
Done %s (100.0%%)"
,
p_update
->
release
.
psz_url
,
psz_size
)
!=
-
1
)
...
...
@@ -1115,9 +1241,54 @@ void update_DownloadReal( update_download_thread_t *p_udt )
}
}
else
remove
(
psz_destfile
);
{
unlink
(
psz_destfile
);
/* FIXME: use (and write) utf8_unlink() ? */
goto
end
;
}
error:
signature_packet_v3_t
sign
;
if
(
download_signature
(
VLC_OBJECT
(
p_udt
),
&
sign
,
p_update
->
release
.
psz_url
)
!=
VLC_SUCCESS
)
{
msg_Err
(
p_udt
,
"Couldn't download signature of status file"
);
goto
end
;
}
if
(
sign
.
type
!=
BINARY_SIGNATURE
)
{
msg_Err
(
p_udt
,
"Invalid signature type"
);
goto
end
;
}
uint8_t
*
p_hash
=
hash_sha1_from_file
(
psz_destfile
,
&
sign
);
if
(
!
p_hash
)
{
msg_Err
(
p_udt
,
"Unable to hash %s"
,
psz_destfile
);
unlink
(
psz_destfile
);
goto
end
;
}
if
(
p_hash
[
0
]
!=
sign
.
hash_verification
[
0
]
||
p_hash
[
1
]
!=
sign
.
hash_verification
[
1
]
)
{
msg_Err
(
p_udt
,
"Bad SHA1 hash for %s"
,
psz_destfile
);
unlink
(
psz_destfile
);
goto
end
;
}
if
(
verify_signature
(
VLC_OBJECT
(
p_udt
),
sign
.
r
,
sign
.
s
,
&
p_update
->
p_pkey
->
key
,
p_hash
)
!=
VLC_SUCCESS
)
{
msg_Err
(
p_udt
,
"BAD SIGNATURE for %s"
,
psz_destfile
);
free
(
p_hash
);
unlink
(
psz_destfile
);
goto
end
;
}
msg_Info
(
p_udt
,
"%s authenticated"
,
psz_destfile
);
free
(
p_hash
);
end:
if
(
p_stream
)
stream_Delete
(
p_stream
);
if
(
p_file
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment