Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
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
Commits
a41a6d3d
Commit
a41a6d3d
authored
Apr 29, 2014
by
Simona-Marinela Prodea
Committed by
Jean-Baptiste Kempf
May 03, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
DCP: read encrypted DCP with KDM files
Uses libgcrypt Signed-off-by:
Jean-Baptiste Kempf
<
jb@videolan.org
>
parent
c7e0dfcc
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
939 additions
and
95 deletions
+939
-95
modules/access/Makefile.am
modules/access/Makefile.am
+5
-1
modules/access/dcp/dcp.cpp
modules/access/dcp/dcp.cpp
+36
-4
modules/access/dcp/dcpdecrypt.cpp
modules/access/dcp/dcpdecrypt.cpp
+673
-0
modules/access/dcp/dcpparser.cpp
modules/access/dcp/dcpparser.cpp
+132
-88
modules/access/dcp/dcpparser.h
modules/access/dcp/dcpparser.h
+93
-2
No files found.
modules/access/Makefile.am
View file @
a41a6d3d
...
...
@@ -9,12 +9,16 @@ AM_CPPFLAGS += -I$(srcdir)/access
libattachment_plugin_la_SOURCES
=
access/attachment.c
access_LTLIBRARIES
+=
libattachment_plugin.la
libdcp_plugin_la_SOURCES
=
access/dcp/dcpparser.h access/dcp/dcp.cpp access/dcp/dcpparser.cpp
libdcp_plugin_la_SOURCES
=
access/dcp/dcpparser.h access/dcp/dcp.cpp access/dcp/dcpparser.cpp
access/dcp/dcpdecrypt.cpp
if
HAVE_ASDCP
libdcp_plugin_la_CPPFLAGS
=
$(AM_CPPFLAGS)
$(ASDCP_CFLAGS)
libdcp_plugin_la_LIBADD
=
$(AM_LIBADD)
$(ASDCP_LIBS)
if
HAVE_GCRYPT
libdcp_plugin_la_CPPFLAGS
+=
$(GCRYPT_CFLAGS)
libdcp_plugin_la_LIBADD
+=
$(GCRYPT_LIBS)
access_LTLIBRARIES
+=
libdcp_plugin.la
endif
endif
libfilesystem_plugin_la_SOURCES
=
access/fs.h access/file.c access/directory.c access/fs.c
libfilesystem_plugin_la_CPPFLAGS
=
$(AM_CPPFLAGS)
...
...
modules/access/dcp/dcp.cpp
View file @
a41a6d3d
...
...
@@ -41,6 +41,8 @@
#endif
#define __STDC_CONSTANT_MACROS 1
#define KDM_HELP_TEXT "KDM file"
#define KDM_HELP_LONG_TEXT "Path to Key Delivery Message XML file"
/* VLC core API headers */
#include <vlc_common.h>
...
...
@@ -72,6 +74,7 @@ static void Close( vlc_object_t * );
vlc_module_begin
()
set_shortname
(
N_
(
"DCP"
)
)
add_shortcut
(
"dcp"
)
add_loadfile
(
"kdm"
,
""
,
KDM_HELP_TEXT
,
KDM_HELP_LONG_TEXT
,
false
)
set_description
(
N_
(
"Digital Cinema Package module"
)
)
set_capability
(
"access_demux"
,
0
)
set_category
(
CAT_INPUT
)
...
...
@@ -604,6 +607,7 @@ static int Demux( demux_t *p_demux )
block_t
*
p_video_frame
=
NULL
,
*
p_audio_frame
=
NULL
;
PCM
::
FrameBuffer
AudioFrameBuff
(
p_sys
->
i_audio_buffer
);
AESDecContext
video_aes_ctx
,
audio_aes_ctx
;
/* swaping video reels */
if
(
p_sys
->
frame_no
==
p_sys
->
p_dcp
->
video_reels
[
p_sys
->
i_video_reel
].
i_absolute_end
)
...
...
@@ -632,6 +636,20 @@ static int Demux( demux_t *p_demux )
}
/* video frame */
/* initialize AES context, if reel is encrypted */
if
(
p_sys
&&
p_sys
->
p_dcp
&&
p_sys
->
p_dcp
->
video_reels
.
size
()
>
p_sys
->
i_video_reel
&&
p_sys
->
p_dcp
->
video_reels
[
p_sys
->
i_video_reel
].
p_key
)
{
if
(
!
ASDCP_SUCCESS
(
video_aes_ctx
.
InitKey
(
p_sys
->
p_dcp
->
video_reels
[
p_sys
->
i_video_reel
].
p_key
->
getKey
()
)
)
)
{
msg_Err
(
p_demux
,
"ASDCP failed to initialize AES key"
);
goto
error
;
}
}
switch
(
p_sys
->
PictureEssType
)
{
case
ESS_JPEG_2000
:
...
...
@@ -646,13 +664,13 @@ static int Demux( demux_t *p_demux )
goto
error_asdcp
;
if
(
p_sys
->
PictureEssType
==
ESS_JPEG_2000_S
)
{
if
(
!
ASDCP_SUCCESS
(
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_PicMXFSReader
->
ReadFrame
(
nextFrame
,
JP2K
::
SP_LEFT
,
PicFrameBuff
,
0
,
0
))
)
{
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_PicMXFSReader
->
ReadFrame
(
nextFrame
,
JP2K
::
SP_LEFT
,
PicFrameBuff
,
&
video_aes_ctx
,
0
))
)
{
PicFrameBuff
.
SetData
(
0
,
0
);
goto
error_asdcp
;
}
}
else
{
if
(
!
ASDCP_SUCCESS
(
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_PicMXFReader
->
ReadFrame
(
nextFrame
,
PicFrameBuff
,
0
,
0
))
)
{
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_PicMXFReader
->
ReadFrame
(
nextFrame
,
PicFrameBuff
,
&
video_aes_ctx
,
0
))
)
{
PicFrameBuff
.
SetData
(
0
,
0
);
goto
error_asdcp
;
}
...
...
@@ -670,7 +688,7 @@ static int Demux( demux_t *p_demux )
goto
error_asdcp
;
if
(
!
ASDCP_SUCCESS
(
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_VideoMXFReader
->
ReadFrame
(
p_sys
->
frame_no
+
p_sys
->
p_dcp
->
video_reels
[
p_sys
->
i_video_reel
].
i_correction
,
VideoFrameBuff
,
0
,
0
))
)
{
p_sys
->
v_videoReader
[
p_sys
->
i_video_reel
].
p_VideoMXFReader
->
ReadFrame
(
p_sys
->
frame_no
+
p_sys
->
p_dcp
->
video_reels
[
p_sys
->
i_video_reel
].
i_correction
,
VideoFrameBuff
,
&
video_aes_ctx
,
0
))
)
{
VideoFrameBuff
.
SetData
(
0
,
0
);
goto
error_asdcp
;
}
...
...
@@ -690,13 +708,27 @@ static int Demux( demux_t *p_demux )
if
(
(
p_audio_frame
=
block_Alloc
(
p_sys
->
i_audio_buffer
))
==
NULL
)
{
goto
error
;
}
/* initialize AES context, if reel is encrypted */
if
(
p_sys
&&
p_sys
->
p_dcp
&&
p_sys
->
p_dcp
->
audio_reels
.
size
()
>
p_sys
->
i_audio_reel
&&
p_sys
->
p_dcp
->
audio_reels
[
p_sys
->
i_audio_reel
].
p_key
)
{
if
(
!
ASDCP_SUCCESS
(
audio_aes_ctx
.
InitKey
(
p_sys
->
p_dcp
->
audio_reels
[
p_sys
->
i_audio_reel
].
p_key
->
getKey
()
)
)
)
{
msg_Err
(
p_demux
,
"ASDCP failed to initialize AES key"
);
goto
error
;
}
}
if
(
!
ASDCP_SUCCESS
(
AudioFrameBuff
.
SetData
(
p_audio_frame
->
p_buffer
,
p_sys
->
i_audio_buffer
))
)
{
goto
error_asdcp
;
}
if
(
!
ASDCP_SUCCESS
(
p_sys
->
v_audioReader
[
p_sys
->
i_audio_reel
].
p_AudioMXFReader
->
ReadFrame
(
p_sys
->
frame_no
+
p_sys
->
p_dcp
->
audio_reels
[
p_sys
->
i_audio_reel
].
i_correction
,
AudioFrameBuff
,
0
,
0
))
)
{
p_sys
->
v_audioReader
[
p_sys
->
i_audio_reel
].
p_AudioMXFReader
->
ReadFrame
(
p_sys
->
frame_no
+
p_sys
->
p_dcp
->
audio_reels
[
p_sys
->
i_audio_reel
].
i_correction
,
AudioFrameBuff
,
&
audio_aes_ctx
,
0
))
)
{
AudioFrameBuff
.
SetData
(
0
,
0
);
goto
error_asdcp
;
}
...
...
modules/access/dcp/dcpdecrypt.cpp
0 → 100644
View file @
a41a6d3d
/*****************************************************************************
* Copyright (C) 2013 VLC authors and VideoLAN
*
* Author:
* Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
*
* 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 version 2.1 of the License, or
* (at your option) any later version.
*
* 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 Lesser General Public License for more details.
*
* 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.
*****************************************************************************/
/**
* The code used for reading a DER-encoded private key, that is,
* RSAKey::parseTag function and RSAKey::readDER function,
* is taken almost as is from libgcrypt tests/fipsdrv.c
*/
/**
* @file dcpdecrypt.cpp
* @brief Handle encrypted DCPs
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* VLC core API headers */
#include <vlc_common.h>
#include <vlc_xml.h>
#include <vlc_strings.h>
#include <fstream>
#include <algorithm>
#include <cctype>
#include "dcpparser.h"
/* creates a printable, RFC 4122-conform UUID, from a given array of bytes
*/
static
string
createUUID
(
unsigned
char
*
ps_string
)
{
string
s_uuid
;
char
h
[
3
];
int
i
,
ret
;
if
(
!
ps_string
)
return
""
;
try
{
s_uuid
.
append
(
"urn:uuid:"
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
ret
=
snprintf
(
h
,
3
,
"%02hhx"
,
ps_string
[
i
]
);
/* each byte can be written as 2 hex digits */
if
(
ret
!=
2
)
return
""
;
s_uuid
.
append
(
h
);
if
(
i
==
3
||
i
==
5
||
i
==
7
||
i
==
9
)
s_uuid
.
append
(
"-"
);
}
}
catch
(
...
)
{
return
""
;
}
return
s_uuid
;
}
/*
* KDM class
*/
int
KDM
::
Parse
()
{
string
s_node
,
s_value
;
const
string
s_root_node
=
"DCinemaSecurityMessage"
;
int
type
;
AESKeyList
*
_p_key_list
=
NULL
;
/* init XML parser */
if
(
this
->
OpenXml
()
)
{
msg_Err
(
p_demux
,
"failed to initialize KDM XML parser"
);
return
VLC_EGENERIC
;
}
msg_Dbg
(
this
->
p_demux
,
"parsing KDM..."
);
/* read first node and check if it is a KDM */
if
(
!
(
(
XML_READER_STARTELEM
==
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
s_node
)
)
&&
(
s_node
==
s_root_node
)
)
)
{
msg_Err
(
this
->
p_demux
,
"not a valid XML KDM"
);
goto
error
;
}
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
s_node
)
)
>
0
)
if
(
type
==
XML_READER_STARTELEM
&&
s_node
==
"AuthenticatedPrivate"
)
{
_p_key_list
=
new
(
nothrow
)
AESKeyList
;
if
(
unlikely
(
_p_key_list
==
NULL
)
)
goto
error
;
p_dcp
->
p_key_list
=
_p_key_list
;
if
(
this
->
ParsePrivate
(
s_node
,
type
)
)
goto
error
;
/* keys found, so break */
break
;
}
if
(
(
_p_key_list
==
NULL
)
||
(
_p_key_list
->
size
()
==
0
)
)
{
msg_Err
(
p_demux
,
"Key list empty"
);
goto
error
;
}
/* close KDM XML */
this
->
CloseXml
();
return
VLC_SUCCESS
;
error:
this
->
CloseXml
();
return
VLC_EGENERIC
;
}
int
KDM
::
ParsePrivate
(
const
string
_s_node
,
int
_i_type
)
{
string
s_node
;
int
i_type
;
AESKey
*
p_key
;
/* check that we are where we're supposed to be */
if
(
_i_type
!=
XML_READER_STARTELEM
)
goto
error
;
if
(
_s_node
!=
"AuthenticatedPrivate"
)
goto
error
;
/* loop on EncryptedKey nodes */
while
(
(
i_type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
s_node
)
)
>
0
)
{
switch
(
i_type
)
{
case
XML_READER_STARTELEM
:
if
(
s_node
!=
"enc:EncryptedKey"
)
goto
error
;
p_key
=
new
(
nothrow
)
AESKey
(
this
->
p_demux
);
if
(
unlikely
(
p_key
==
NULL
)
)
return
VLC_EGENERIC
;
if
(
p_key
->
Parse
(
p_xmlReader
,
s_node
,
i_type
)
)
{
delete
p_key
;
return
VLC_EGENERIC
;
}
p_dcp
->
p_key_list
->
push_back
(
p_key
);
break
;
case
XML_READER_ENDELEM
:
if
(
s_node
==
_s_node
)
return
VLC_SUCCESS
;
break
;
default:
case
XML_READER_TEXT
:
goto
error
;
}
}
/* shouldn't get here */
error:
msg_Err
(
p_demux
,
"error while parsing AuthenticatedPrivate portion of KDM"
);
return
VLC_EGENERIC
;
}
/*
* AESKey class
*/
int
AESKey
::
Parse
(
xml_reader_t
*
p_xml_reader
,
string
_s_node
,
int
_i_type
)
{
string
s_node
;
string
s_value
;
int
i_type
;
if
(
_i_type
!=
XML_READER_STARTELEM
)
goto
error
;
if
(
_s_node
!=
"enc:EncryptedKey"
)
goto
error
;
while
(
(
i_type
=
XmlFile
::
ReadNextNode
(
p_xml_reader
,
s_node
)
)
>
0
)
{
switch
(
i_type
)
{
case
XML_READER_STARTELEM
:
if
(
s_node
==
"enc:CipherValue"
)
{
if
(
XmlFile
::
ReadEndNode
(
p_xml_reader
,
s_node
,
i_type
,
s_value
)
)
goto
error
;
if
(
this
->
decryptRSA
(
s_value
)
)
return
VLC_EGENERIC
;
}
break
;
case
XML_READER_ENDELEM
:
if
(
s_node
==
_s_node
)
return
VLC_SUCCESS
;
break
;
default:
case
XML_READER_TEXT
:
goto
error
;
}
}
/* shouldn't get here */
error:
msg_Err
(
this
->
p_demux
,
"error while parsing EncryptedKey"
);
return
VLC_EGENERIC
;
}
/* decrypts the RSA encrypted text read from the XML file,
* and saves the AES key and the other needed info
* uses libgcrypt for decryption
*/
int
AESKey
::
decryptRSA
(
string
s_cipher_text_b64
)
{
RSAKey
rsa_key
(
this
->
p_demux
);
unsigned
char
*
ps_cipher_text
=
NULL
;
unsigned
char
*
ps_plain_text
=
NULL
;
gcry_mpi_t
cipher_text_mpi
=
NULL
;
gcry_sexp_t
cipher_text_sexp
=
NULL
;
gcry_sexp_t
plain_text_sexp
=
NULL
;
gcry_mpi_t
plain_text_mpi
=
NULL
;
gcry_sexp_t
tmp_sexp
=
NULL
;
gcry_error_t
err
;
size_t
length
;
int
i_ret
=
VLC_EGENERIC
;
/* get RSA private key file path */
if
(
rsa_key
.
setPath
()
)
goto
end
;
/* read private key from file */
if
(
rsa_key
.
readPEM
()
)
goto
end
;
/* remove spaces and newlines from encoded cipher text
* (usually added for indentation in XML files)
* */
try
{
s_cipher_text_b64
.
erase
(
remove_if
(
s_cipher_text_b64
.
begin
(),
s_cipher_text_b64
.
end
(),
static_cast
<
int
(
*
)(
int
)
>
(
isspace
)
),
s_cipher_text_b64
.
end
()
);
}
catch
(
...
)
{
msg_Err
(
this
->
p_demux
,
"error while handling string"
);
goto
end
;
}
/* decode cipher from BASE64 to binary */
if
(
!
(
length
=
vlc_b64_decode_binary
(
&
ps_cipher_text
,
s_cipher_text_b64
.
c_str
()
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not decode cipher from Base64"
);
goto
end
;
}
/* initialize libgcrypt */
vlc_gcrypt_init
();
/* create S-expression for ciphertext */
if
(
(
err
=
gcry_mpi_scan
(
&
cipher_text_mpi
,
GCRYMPI_FMT_USG
,
ps_cipher_text
,
256
,
NULL
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not scan MPI from cipher text: %s"
,
gcry_strerror
(
err
)
);
goto
end
;
}
if
(
(
err
=
gcry_sexp_build
(
&
cipher_text_sexp
,
NULL
,
"(enc-val(flags oaep)(rsa(a %m)))"
,
cipher_text_mpi
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not build S-expression for cipher text: %s"
,
gcry_strerror
(
err
)
);
goto
end
;
}
/* decrypt */
if
(
(
err
=
gcry_pk_decrypt
(
&
plain_text_sexp
,
cipher_text_sexp
,
rsa_key
.
priv_key
)
)
)
{
msg_Err
(
this
->
p_demux
,
"error while decrypting RSA encrypted info: %s"
,
gcry_strerror
(
err
)
);
goto
end
;
}
/* extract plain-text from S-expression */
if
(
!
(
tmp_sexp
=
gcry_sexp_find_token
(
plain_text_sexp
,
"value"
,
0
)
)
)
/* when using padding flags, the decrypted S-expression is of the form
* "(value <plaintext>)", where <plaintext> is an MPI */
{
msg_Err
(
this
->
p_demux
,
"decrypted text is in an unexpected form; decryption may have failed"
);
goto
end
;
}
/* we could have used the gcry_sexp_nth_data to get the data directly,
* but as that function is newly introduced (libgcrypt v1.6),
* we prefer compatibility, even though that means passing the data through an MPI first */
if
(
!
(
plain_text_mpi
=
gcry_sexp_nth_mpi
(
tmp_sexp
,
1
,
GCRYMPI_FMT_USG
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not extract MPI from decrypted S-expression"
);
goto
end
;
}
if
(
(
err
=
gcry_mpi_aprint
(
GCRYMPI_FMT_USG
,
&
ps_plain_text
,
&
length
,
plain_text_mpi
)
)
)
{
msg_Err
(
this
->
p_demux
,
"error while extracting plain text from MPI: %s"
,
gcry_strerror
(
err
)
);
goto
end
;
}
/* interpret the plaintext data */
switch
(
length
)
{
case
138
:
/* SMPTE DCP */
if
(
this
->
extractInfo
(
ps_plain_text
,
true
)
)
goto
end
;
break
;
case
134
:
/* Interop DCP */
if
(
this
->
extractInfo
(
ps_plain_text
,
false
)
)
goto
end
;
break
;
case
-
1
:
msg_Err
(
this
->
p_demux
,
"could not decrypt"
);
goto
end
;
default:
msg_Err
(
this
->
p_demux
,
"CipherValue field length does not match SMPTE nor Interop standards"
);
goto
end
;
}
i_ret
=
VLC_SUCCESS
;
end:
free
(
ps_cipher_text
);
gcry_mpi_release
(
cipher_text_mpi
);
gcry_sexp_release
(
cipher_text_sexp
);
gcry_sexp_release
(
plain_text_sexp
);
gcry_mpi_release
(
plain_text_mpi
);
gcry_sexp_release
(
tmp_sexp
);
gcry_free
(
ps_plain_text
);
return
i_ret
;
}
/* extracts and saves the AES key info from the plaintext;
* parameter smpte is true for SMPTE DCP, false for Interop;
* see SMPTE 430-1-2006, section 6.1.2 for the exact structure of the plaintext
*/
int
AESKey
::
extractInfo
(
unsigned
char
*
ps_plain_text
,
bool
smpte
)
{
string
s_rsa_structID
(
"f1dc124460169a0e85bc300642f866ab"
);
/* unique Structure ID for all RSA-encrypted AES keys in a KDM */
string
s_carrier
;
char
psz_hex
[
3
];
int
i_ret
,
i_pos
=
0
;
/* check for the structure ID */
while
(
i_pos
<
16
)
{
i_ret
=
snprintf
(
psz_hex
,
3
,
"%02hhx"
,
ps_plain_text
[
i_pos
]
);
if
(
i_ret
!=
2
)
{
msg_Err
(
this
->
p_demux
,
"error while extracting structure ID from decrypted cipher"
);
return
VLC_EGENERIC
;
}
try
{
s_carrier
.
append
(
psz_hex
);
}
catch
(
...
)
{
msg_Err
(
this
->
p_demux
,
"error while handling string"
);
return
VLC_EGENERIC
;
}
i_pos
++
;
}
if
(
s_carrier
.
compare
(
s_rsa_structID
)
)
{
msg_Err
(
this
->
p_demux
,
"incorrect RSA structure ID: KDM may be broken"
);
return
VLC_EGENERIC
;
}
i_pos
+=
36
;
/* TODO thumbprint, CPL ID */
if
(
smpte
)
/* only SMPTE DCPs have the 4-byte "KeyType" field */
i_pos
+=
4
;
/* extract the AES key UUID */
if
(
(
this
->
s_key_id
=
createUUID
(
ps_plain_text
+
i_pos
)
).
empty
()
)
{
msg_Err
(
this
->
p_demux
,
"error while extracting AES Key UUID"
);
return
VLC_EGENERIC
;
}
i_pos
+=
16
;
i_pos
+=
50
;
/* TODO KeyEpoch */
/* extract the AES key */
memcpy
(
this
->
ps_key
,
ps_plain_text
+
i_pos
,
16
);
return
VLC_SUCCESS
;
}
/*
* RSAKey class
*/
/*
* gets the private key path (always stored in the VLC config dir and called "priv.key" )
*/
int
RSAKey
::
setPath
(
)
{
char
*
psz_config_dir
=
NULL
;
if
(
!
(
psz_config_dir
=
config_GetUserDir
(
VLC_CONFIG_DIR
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not read user config dir"
);
goto
error
;
}
try
{
this
->
s_path
.
assign
(
psz_config_dir
);
this
->
s_path
.
append
(
"/priv.key"
);
}
catch
(
...
)
{
msg_Err
(
this
->
p_demux
,
"error while handling string"
);
goto
error
;
}
free
(
psz_config_dir
);
return
VLC_SUCCESS
;
error:
free
(
psz_config_dir
);
return
VLC_EGENERIC
;
}
/*
* reads the RSA private key from file
* the file must be conform to PCKS#1, PEM-encoded, unencrypted
*/
int
RSAKey
::
readPEM
(
)
{
string
s_header_tag
(
"-----BEGIN RSA PRIVATE KEY-----"
);
string
s_footer_tag
(
"-----END RSA PRIVATE KEY-----"
);
string
s_line
;
string
s_data_b64
;
unsigned
char
*
ps_data_der
=
NULL
;
size_t
length
;
/* open key file */
ifstream
file
(
this
->
s_path
.
c_str
(),
ios
::
in
);
if
(
!
file
.
is_open
()
)
{
msg_Err
(
this
->
p_demux
,
"could not open private key file"
);
goto
error
;
}
/* check for header tag */
if
(
!
getline
(
file
,
s_line
)
)
{
msg_Err
(
this
->
p_demux
,
"could not read private key file"
);
goto
error
;
}
if
(
s_line
.
compare
(
s_header_tag
)
)
{
msg_Err
(
this
->
p_demux
,
"unexpected header tag found in private key file"
);
goto
error
;
}
/* read file until footer tag is found */
while
(
getline
(
file
,
s_line
)
)
{
if
(
!
s_line
.
compare
(
s_footer_tag
)
)
break
;
try
{
s_data_b64
.
append
(
s_line
);
}
catch
(
...
)
{
msg_Err
(
this
->
p_demux
,
"error while handling string"
);
goto
error
;
}
}
if
(
!
file
)
{
msg_Err
(
this
->
p_demux
,
"error while reading private key file; footer tag may be missing"
);
goto
error
;
}
/* decode data from Base64 */
if
(
!
(
length
=
vlc_b64_decode_binary
(
&
ps_data_der
,
s_data_b64
.
c_str
()
)
)
)
{
msg_Err
(
this
->
p_demux
,
"could not decode from Base64"
);
goto
error
;
}
/* extract key S-expression from DER-encoded data */
if
(
this
->
readDER
(
ps_data_der
,
length
)
)
goto
error
;
/* clear data */
free
(
ps_data_der
);
return
VLC_SUCCESS
;
error:
free
(
ps_data_der
);
return
VLC_EGENERIC
;
}
/*
* Parse the DER-encoded data at ps_data_der
* saving the key in an S-expression
*/
int
RSAKey
::
readDER
(
unsigned
char
const
*
ps_data_der
,
size_t
length
)
{
struct
tag_info
tag_inf
;
gcry_mpi_t
key_params
[
8
];
gcry_error_t
err
;
int
i
;
/* parse the ASN1 structure */
if
(
parseTag
(
&
ps_data_der
,
&
length
,
&
tag_inf
)
||
tag_inf
.
tag
!=
TAG_SEQUENCE
||
tag_inf
.
class_
||
!
tag_inf
.
cons
||
tag_inf
.
ndef
)
goto
bad_asn1
;
if
(
parseTag
(
&
ps_data_der
,
&
length
,
&
tag_inf
)
||
tag_inf
.
tag
!=
TAG_INTEGER
||
tag_inf
.
class_
||
tag_inf
.
cons
||
tag_inf
.
ndef
)
goto
bad_asn1
;
if
(
tag_inf
.
length
!=
1
||
*
ps_data_der
)
goto
bad_asn1
;
/* The value of the first integer is no 0. */
ps_data_der
+=
tag_inf
.
length
;
length
-=
tag_inf
.
length
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
if
(
parseTag
(
&
ps_data_der
,
&
length
,
&
tag_inf
)
||
tag_inf
.
tag
!=
TAG_INTEGER
||
tag_inf
.
class_
||
tag_inf
.
cons
||
tag_inf
.
ndef
)
goto
bad_asn1
;
err
=
gcry_mpi_scan
(
key_params
+
i
,
GCRYMPI_FMT_USG
,
ps_data_der
,
tag_inf
.
length
,
NULL
);
if
(
err
)
{
msg_Err
(
this
->
p_demux
,
"error scanning RSA parameter %d: %s"
,
i
,
gpg_strerror
(
err
)
);
goto
error
;
}
ps_data_der
+=
tag_inf
.
length
;
length
-=
tag_inf
.
length
;
}
/* Convert from OpenSSL parameter ordering to the OpenPGP order.
* First check that p < q; if not swap p and q and recompute u.
*/
if
(
gcry_mpi_cmp
(
key_params
[
3
],
key_params
[
4
]
)
>
0
)
{
gcry_mpi_swap
(
key_params
[
3
],
key_params
[
4
]
);
gcry_mpi_invm
(
key_params
[
7
],
key_params
[
3
],
key_params
[
4
]
);
}
/* Build the S-expression. */
err
=
gcry_sexp_build
(
&
this
->
priv_key
,
NULL
,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))"
,
key_params
[
0
],
key_params
[
1
],
key_params
[
2
],
key_params
[
3
],
key_params
[
4
],
key_params
[
7
]
);
if
(
err
)
{
msg_Err
(
this
->
p_demux
,
"error building S-expression: %s"
,
gpg_strerror
(
err
)
);
goto
error
;
}
/* clear data */
for
(
i
=
0
;
i
<
8
;
i
++
)
gcry_mpi_release
(
key_params
[
i
]
);
return
VLC_SUCCESS
;
bad_asn1:
msg_Err
(
this
->
p_demux
,
"could not parse ASN1 structure; key might be corrupted"
);
error:
for
(
i
=
0
;
i
<
8
;
i
++
)
gcry_mpi_release
(
key_params
[
i
]
);
return
VLC_EGENERIC
;
}
/*
* Parse the buffer at the address BUFFER which consists of the number
* of octets as stored at BUFLEN. Return the tag and the length part
* from the TLV triplet. Update BUFFER and BUFLEN on success. Checks
* that the encoded length does not exhaust the length of the provided
* buffer.
*/
int
RSAKey
::
parseTag
(
unsigned
char
const
**
buffer
,
size_t
*
buflen
,
struct
tag_info
*
ti
)
{
int
c
;
unsigned
long
tag
;
const
unsigned
char
*
buf
=
*
buffer
;
size_t
length
=
*
buflen
;
ti
->
length
=
0
;
ti
->
ndef
=
0
;
ti
->
nhdr
=
0
;
/* Get the tag */
if
(
!
length
)
return
-
1
;
/* Premature EOF. */
c
=
*
buf
++
;
length
--
;
ti
->
nhdr
++
;
ti
->
class_
=
(
c
&
0xc0
)
>>
6
;
ti
->
cons
=
!!
(
c
&
0x20
);
tag
=
(
c
&
0x1f
);
if
(
tag
==
0x1f
)
{
tag
=
0
;
do
{
tag
<<=
7
;
if
(
!
length
)
return
-
1
;
/* Premature EOF. */
c
=
*
buf
++
;
length
--
;
ti
->
nhdr
++
;
tag
|=
(
c
&
0x7f
);
}
while
(
(
c
&
0x80
)
);
}
ti
->
tag
=
tag
;
/* Get the length */
if
(
!
length
)
return
-
1
;
/* Premature EOF. */
c
=
*
buf
++
;
length
--
;
ti
->
nhdr
++
;
if
(
!
(
c
&
0x80
)
)
ti
->
length
=
c
;
else
if
(
c
==
0x80
)
ti
->
ndef
=
1
;
else
if
(
c
==
0xff
)
return
-
1
;
/* Forbidden length value. */
else
{
unsigned
long
len
=
0
;
int
count
=
c
&
0x7f
;
for
(;
count
;
count
--
)
{
len
<<=
8
;
if
(
!
length
)
return
-
1
;
/* Premature EOF. */
c
=
*
buf
++
;
length
--
;
ti
->
nhdr
++
;
len
|=
(
c
&
0xff
);
}
ti
->
length
=
len
;
}
if
(
ti
->
class_
==
0
&&
!
ti
->
tag
)
ti
->
length
=
0
;
if
(
ti
->
length
>
length
)
return
-
1
;
/* Data larger than buffer. */
*
buffer
=
buf
;
*
buflen
=
length
;
return
0
;
}
modules/access/dcp/dcpparser.cpp
View file @
a41a6d3d
...
...
@@ -9,6 +9,7 @@
* Anthony Giniers
* Ludovic Hoareau
* Loukmane Dessai
* Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
*
* 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
...
...
@@ -48,34 +49,6 @@
using
namespace
std
;
static
int
ReadNextNode
(
xml_reader_t
*
p_xmlReader
,
string
&
p_node
)
{
const
char
*
c_node
;
int
i
;
i
=
xml_ReaderNextNode
(
p_xmlReader
,
&
c_node
);
p_node
=
c_node
;
return
i
;
}
static
int
ReadEndNode
(
xml_reader_t
*
p_xmlReader
,
string
p_node
,
int
p_type
,
string
&
s_value
)
{
string
node
;
if
(
xml_ReaderIsEmptyElement
(
p_xmlReader
)
)
return
0
;
if
(
p_type
!=
XML_READER_STARTELEM
)
return
-
1
;
if
(
ReadNextNode
(
p_xmlReader
,
node
)
==
XML_READER_TEXT
)
{
s_value
=
node
;
if
((
ReadNextNode
(
p_xmlReader
,
node
)
==
XML_READER_ENDELEM
)
&&
node
==
p_node
)
return
0
;
}
return
-
1
;
}
typedef
enum
{
CHUNK_UNKNOWN
=
0
,
CHUNK_PATH
,
...
...
@@ -161,7 +134,7 @@ int Chunk::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type){
if
(
p_node
!=
"Chunk"
)
return
-
1
;
/* loop on Chunks Node */
while
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
...
...
@@ -169,7 +142,7 @@ int Chunk::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type){
for
(
ChunkTag_t
i
=
CHUNK_PATH
;
i
<=
CHUNK_LENGTH
;
i
=
ChunkTag_t
(
i
+
1
))
{
if
(
node
==
names
[
i
-
1
])
{
chunk_tag
=
i
;
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
switch
(
chunk_tag
)
{
case
CHUNK_PATH
:
...
...
@@ -230,11 +203,13 @@ AssetMap::~AssetMap() { }
int
AssetMap
::
Parse
(
)
{
int
type
=
0
;
int
retval
;
int
reel_nbr
=
0
;
int
index
=
0
;
int
sum_duration_vid
=
0
;
int
sum_duration_aud
=
0
;
string
node
;
char
*
psz_kdm_path
;
CPL
*
cpl
;
Reel
*
reel
;
...
...
@@ -251,7 +226,7 @@ int AssetMap::Parse ( )
/* reading ASSETMAP file to get the asset_list */
msg_Dbg
(
p_demux
,
"reading ASSETMAP file..."
);
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
if
(
(
type
==
XML_READER_STARTELEM
)
&&
(
node
==
"AssetList"
))
{
_p_asset_list
=
new
(
nothrow
)
AssetList
();
if
(
unlikely
(
_p_asset_list
==
NULL
)
)
{
...
...
@@ -337,6 +312,29 @@ int AssetMap::Parse ( )
return
-
1
;
}
/* KDM, if needed */
for
(
AssetList
::
iterator
iter
=
_p_asset_list
->
begin
();
iter
!=
_p_asset_list
->
end
();
++
iter
)
if
(
!
(
*
iter
)
->
getKeyId
().
empty
()
)
{
msg_Dbg
(
p_demux
,
"DCP is encrypted, searching KDM file..."
);
psz_kdm_path
=
var_InheritString
(
p_demux
,
"kdm"
);
if
(
!
psz_kdm_path
||
!*
psz_kdm_path
)
{
msg_Err
(
p_demux
,
"cryptographic key IDs found in CPL and no path to KDM given"
);
free
(
psz_kdm_path
);
this
->
CloseXml
();
return
VLC_EGENERIC
;
}
KDM
p_kdm
(
p_demux
,
psz_kdm_path
,
p_dcp
);
free
(
psz_kdm_path
);
if
(
(
retval
=
p_kdm
.
Parse
()
)
)
{
this
->
CloseXml
();
return
retval
;
}
break
;
}
reel_nbr
=
cpl
->
getReelList
().
size
();
for
(
index
=
0
;
index
!=
reel_nbr
;
++
index
)
{
...
...
@@ -356,6 +354,7 @@ int AssetMap::Parse ( )
video
.
i_duration
=
asset
->
getDuration
();
video
.
i_correction
=
video
.
i_entrypoint
-
sum_duration_vid
+
video
.
i_duration
;
video
.
i_absolute_end
=
sum_duration_vid
;
video
.
p_key
=
asset
->
getAESKeyById
(
p_dcp
->
p_key_list
,
asset
->
getKeyId
()
);
p_dcp
->
video_reels
.
push_back
(
video
);
msg_Dbg
(
this
->
p_demux
,
"Video Track: %s"
,
asset
->
getPath
().
c_str
());
msg_Dbg
(
this
->
p_demux
,
"Entry point: %i"
,
asset
->
getEntryPoint
());
...
...
@@ -378,6 +377,7 @@ int AssetMap::Parse ( )
audio
.
i_duration
=
asset
->
getDuration
();
audio
.
i_correction
=
audio
.
i_entrypoint
-
sum_duration_aud
+
audio
.
i_duration
;
audio
.
i_absolute_end
=
sum_duration_aud
;
audio
.
p_key
=
asset
->
getAESKeyById
(
p_dcp
->
p_key_list
,
asset
->
getKeyId
()
);
p_dcp
->
audio_reels
.
push_back
(
audio
);
msg_Dbg
(
this
->
p_demux
,
"Audio Track: %s"
,
asset
->
getPath
().
c_str
());
msg_Dbg
(
this
->
p_demux
,
"Entry point: %i"
,
asset
->
getEntryPoint
());
...
...
@@ -407,7 +407,7 @@ int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
if
(
p_node
!=
s_root_node
)
return
-
1
;
/* loop on Assets Node */
while
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
...
...
@@ -421,7 +421,7 @@ int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
/* case of <PackinkList/> tag, bur not compliant with SMPTE-429-9 2007*/
if
(
xml_ReaderIsEmptyElement
(
p_xmlReader
))
this
->
b_is_packing_list
=
true
;
else
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
else
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
if
(
s_value
==
"true"
)
this
->
b_is_packing_list
=
true
;
...
...
@@ -432,12 +432,12 @@ int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
this
->
s_path
=
this
->
chunk_vec
[
0
].
getPath
();
break
;
case
ASSET_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
s_id
=
s_value
;
break
;
case
ASSET_ANNOTATION_TEXT
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
s_annotation
=
s_value
;
break
;
...
...
@@ -493,7 +493,7 @@ int Asset::ParsePKL( xml_reader_t *p_xmlReader)
string
s_value
;
const
string
s_root_node
=
"Asset"
;
while
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
...
...
@@ -503,7 +503,7 @@ int Asset::ParsePKL( xml_reader_t *p_xmlReader)
_tag
=
i
;
switch
(
_tag
)
{
case
ASSET_ANNOTATION_TEXT
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
if
(
this
->
s_annotation
.
empty
()
)
this
->
s_annotation
=
s_value
;
...
...
@@ -511,22 +511,22 @@ int Asset::ParsePKL( xml_reader_t *p_xmlReader)
this
->
s_annotation
=
this
->
s_annotation
+
"--"
+
s_value
;
break
;
case
ASSET_HASH
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
s_hash
=
s_value
;
break
;
case
ASSET_SIZE
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
ui_size
=
atol
(
s_value
.
c_str
());
break
;
case
ASSET_TYPE
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
s_type
=
s_value
;
break
;
case
ASSET_ORIGINAL_FILENAME
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
this
->
s_original_filename
=
s_value
;
break
;
...
...
@@ -602,7 +602,7 @@ int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
if
(
p_node
!=
"ChunkList"
)
return
-
1
;
/* loop on Assets Node */
while
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
...
...
@@ -629,6 +629,20 @@ int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
return
-
1
;
}
AESKey
*
Asset
::
getAESKeyById
(
AESKeyList
*
p_key_list
,
const
string
s_id
)
{
/* return NULL if DCP is not encrypted */
if
(
!
p_key_list
||
s_id
.
empty
()
)
return
NULL
;
for
(
AESKeyList
::
iterator
index
=
p_key_list
->
begin
();
index
!=
p_key_list
->
end
();
++
index
)
if
(
(
*
index
)
->
getKeyId
()
==
s_id
)
return
*
index
;
return
NULL
;
}
int
AssetMap
::
ParseAssetList
(
xml_reader_t
*
p_xmlReader
,
const
string
p_node
,
int
p_type
)
{
string
node
;
...
...
@@ -640,7 +654,7 @@ int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, in
if
(
p_node
!=
"AssetList"
)
return
-
1
;
/* loop on AssetList nodes */
while
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
if
(
node
!=
"Asset"
)
...
...
@@ -707,6 +721,35 @@ int XmlFile::OpenXml()
return
0
;
}
int
XmlFile
::
ReadNextNode
(
xml_reader_t
*
p_xmlReader
,
string
&
p_node
)
{
const
char
*
c_node
;
int
i
;
i
=
xml_ReaderNextNode
(
p_xmlReader
,
&
c_node
);
p_node
=
c_node
;
return
i
;
}
int
XmlFile
::
ReadEndNode
(
xml_reader_t
*
p_xmlReader
,
string
p_node
,
int
p_type
,
string
&
s_value
)
{
string
node
;
if
(
xml_ReaderIsEmptyElement
(
p_xmlReader
)
)
return
0
;
if
(
p_type
!=
XML_READER_STARTELEM
)
return
-
1
;
if
(
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
==
XML_READER_TEXT
)
{
s_value
=
node
;
if
(
(
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
)
==
XML_READER_ENDELEM
)
&&
node
==
p_node
)
return
0
;
}
return
-
1
;
}
void
XmlFile
::
CloseXml
()
{
if
(
this
->
p_stream
)
stream_Delete
(
this
->
p_stream
);
...
...
@@ -756,12 +799,12 @@ int PKL::Parse()
return
-
1
;
/* read 1st node and verify that is a PKL*/
if
(
!
(
(
XML_READER_STARTELEM
==
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
&&
if
(
!
(
(
XML_READER_STARTELEM
==
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
&&
(
node
==
s_root_node
)
)
)
{
msg_Err
(
this
->
p_demux
,
"Not a valid XML Packing List"
);
goto
error
;
}
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
PKLTag_t
_tag
=
PKL_UNKNOWN
;
...
...
@@ -784,37 +827,37 @@ int PKL::Parse()
break
;
/* Parse simple/end nodes */
case
PKL_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_id
=
s_value
;
break
;
case
PKL_ISSUE_DATE
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_issue_date
=
s_value
;
break
;
case
PKL_ISSUER
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_issuer
=
s_value
;
break
;
case
PKL_CREATOR
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_creator
=
s_value
;
break
;
case
PKL_ANNOTATION_TEXT
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_annotation
=
s_value
;
break
;
case
PKL_ICON_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_icon_id
=
s_value
;
break
;
case
PKL_GROUP_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_group_id
=
s_value
;
break
;
...
...
@@ -890,7 +933,7 @@ int PKL::ParseAssetList(string p_node, int p_type) {
return
-
1
;
if
(
p_node
!=
"AssetList"
)
return
-
1
;
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
if
(
node
==
"Asset"
)
{
...
...
@@ -923,16 +966,16 @@ int PKL::ParseAsset(string p_node, int p_type) {
return
-
1
;
/* 1st node shall be Id" */
if
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
(
!
((
type
==
XML_READER_STARTELEM
)
&&
(
node
==
"Id"
)))
return
-
1
;
if
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
(
type
==
XML_READER_TEXT
)
{
s_value
=
node
;
if
(
unlikely
(
node
.
empty
()))
return
-
1
;
}
if
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
(
type
==
XML_READER_ENDELEM
)
{
asset
=
AssetMap
::
getAssetById
(
this
->
asset_list
,
s_value
);
if
(
asset
==
NULL
)
...
...
@@ -955,7 +998,7 @@ int PKL::ParseSigner(string p_node, int p_type)
if
(
p_node
!=
"Signer"
)
return
-
1
;
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
/* TODO not implemented. Just parse until end of Signer node */
if
((
node
==
p_node
)
&&
(
type
=
XML_READER_ENDELEM
))
return
0
;
...
...
@@ -975,7 +1018,7 @@ int PKL::ParseSignature(string p_node, int p_type)
if
(
p_node
!=
"ds:Signature"
)
return
-
1
;
while
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
/* TODO not implemented. Just parse until end of Signature node */
if
((
node
==
p_node
)
&&
(
type
=
XML_READER_ENDELEM
))
return
0
;
...
...
@@ -997,15 +1040,15 @@ int Reel::Parse(string p_node, int p_type) {
if
(
p_node
!=
"Reel"
)
return
-
1
;
while
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
if
(
node
==
"Id"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
this
->
s_id
=
s_value
;
}
else
if
(
node
==
"AnnotationText"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
this
->
s_annotation
=
s_value
;
}
else
if
(
node
==
"AssetList"
)
{
...
...
@@ -1060,7 +1103,7 @@ int Reel::ParseAssetList(string p_node, int p_type) {
if
(
p_node
!=
"AssetList"
)
return
-
1
;
while
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
if
(
node
==
"MainPicture"
)
{
...
...
@@ -1105,11 +1148,11 @@ int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
return
-
1
;
/* 1st node shall be Id */
if
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
if
(
!
((
type
==
XML_READER_STARTELEM
)
&&
(
node
==
"Id"
)))
return
-
1
;
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
)
)
return
-
1
;
asset
=
AssetMap
::
getAssetById
(
this
->
p_asset_list
,
s_value
);
...
...
@@ -1117,42 +1160,43 @@ int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
return
-
1
;
while
(
(
!
b_stop_parse
)
&&
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
)
{
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
if
(
node
==
"EditRate"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
}
else
if
(
node
==
"AnnotationText"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
asset
->
setAnnotation
(
s_value
);
}
else
if
(
node
==
"IntrinsicDuration"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
asset
->
setIntrinsicDuration
(
atoi
(
s_value
.
c_str
()));
}
else
if
(
node
==
"EntryPoint"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
asset
->
setEntryPoint
(
atoi
(
s_value
.
c_str
()));
}
else
if
(
node
==
"Duration"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
asset
->
setDuration
(
atoi
(
s_value
.
c_str
()));
}
else
if
(
node
==
"KeyId"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
asset
->
setKeyId
(
s_value
);
}
else
if
(
node
==
"Hash"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
}
else
if
(
node
==
"FrameRate"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
}
else
if
(
node
==
"ScreenAspectRatio"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
}
else
if
(
node
==
"Language"
)
{
if
(
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
if
(
XmlFile
::
ReadEndNode
(
this
->
p_xmlReader
,
node
,
type
,
s_value
))
return
-
1
;
}
else
{
/* unknown tag */
...
...
@@ -1208,7 +1252,7 @@ CPL::CPL(demux_t * p_demux, string s_path, AssetList *_asset_list)
}
/* read 1st node and verify that is a CPL */
if
(
(
type
=
ReadNextNode
(
p_xmlReader
,
node
))
>
0
)
{
if
(
(
type
=
XmlFile
::
ReadNextNode
(
p_xmlReader
,
node
))
>
0
)
{
if
(
(
type
==
XML_READER_STARTELEM
)
&&
(
node
==
"CompositionPlaylist"
)
)
{
this
->
type
=
XML_CPL
;
}
...
...
@@ -1248,13 +1292,13 @@ int CPL::Parse()
return
-
1
;
/* read 1st node and verify that is a CPL*/
if
(
!
(
(
XML_READER_STARTELEM
==
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
&&
if
(
!
(
(
XML_READER_STARTELEM
==
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
&&
(
node
==
s_root_node
)
)
)
{
msg_Err
(
this
->
p_demux
,
"Not a valid XML Packing List"
);
goto
error
;
}
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
CPLTag_t
_tag
=
CPL_UNKNOWN
;
...
...
@@ -1276,42 +1320,42 @@ int CPL::Parse()
break
;
/* Parse simple/end nodes */
case
CPL_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_id
=
s_value
;
break
;
case
CPL_ANNOTATION_TEXT
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_annotation
=
s_value
;
break
;
case
CPL_ICON_ID
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_icon_id
=
s_value
;
break
;
case
CPL_ISSUE_DATE
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_issue_date
=
s_value
;
break
;
case
CPL_ISSUER
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_issuer
=
s_value
;
break
;
case
CPL_CREATOR
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_creator
=
s_value
;
break
;
case
CPL_CONTENT_TITLE
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_content_title
=
s_value
;
break
;
case
CPL_CONTENT_KIND
:
if
(
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
if
(
XmlFile
::
ReadEndNode
(
p_xmlReader
,
node
,
type
,
s_value
)
)
goto
error
;
this
->
s_content_kind
=
s_value
;
break
;
...
...
@@ -1358,7 +1402,7 @@ int CPL::ParseReelList(string p_node, int p_type) {
return
-
1
;
if
(
p_node
!=
"ReelList"
)
return
-
1
;
while
(
(
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
(
(
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
switch
(
type
)
{
case
XML_READER_STARTELEM
:
{
Reel
*
p_reel
=
new
(
nothrow
)
Reel
(
this
->
p_demux
,
this
->
asset_list
,
this
->
p_xmlReader
);
...
...
@@ -1401,7 +1445,7 @@ int CPL::DummyParse(string p_node, int p_type)
if
(
xml_ReaderIsEmptyElement
(
this
->
p_xmlReader
))
return
0
;
while
((
type
=
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
while
((
type
=
XmlFile
::
ReadNextNode
(
this
->
p_xmlReader
,
node
)
)
>
0
)
{
/* TODO not implemented. Just pase until end of input node */
if
((
node
==
p_node
)
&&
(
type
=
XML_READER_ENDELEM
))
return
0
;
...
...
modules/access/dcp/dcpparser.h
View file @
a41a6d3d
...
...
@@ -8,6 +8,7 @@
* Anthony Giniers
* Ludovic Hoareau
* Loukmane Dessai
* Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
*
* 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
...
...
@@ -42,6 +43,10 @@
#include <vlc_demux.h>
#include <vlc_plugin.h>
/* gcrypt headers */
#include <gcrypt.h>
#include <vlc_gcrypt.h>
#include <iostream>
#include <string>
#include <list>
...
...
@@ -67,7 +72,8 @@ typedef enum {
class
Asset
;
class
AssetList
:
public
std
::
list
<
Asset
*>
{};
class
PKL
;
class
AESKey
;
class
AESKeyList
:
public
std
::
list
<
AESKey
*>
{};
/* This struct stores useful information about an MXF for demux() */
struct
info_reel
...
...
@@ -77,6 +83,7 @@ struct info_reel
int
i_duration
;
int
i_correction
;
/* entrypoint - sum of previous durations */
uint32_t
i_absolute_end
;
/* correction + duration */
AESKey
*
p_key
;
};
/* This struct stores the most important information about the DCP */
...
...
@@ -86,12 +93,13 @@ struct dcp_t
vector
<
PKL
*>
pkls
;
AssetList
*
p_asset_list
;
AESKeyList
*
p_key_list
;
vector
<
info_reel
>
audio_reels
;
vector
<
info_reel
>
video_reels
;
dcp_t
()
:
p_asset_list
(
NULL
)
{};
p_asset_list
(
NULL
)
,
p_key_list
(
NULL
)
{};
~
dcp_t
(
)
{
vlc_delete_all
(
pkls
);
...
...
@@ -100,6 +108,10 @@ struct dcp_t
delete
(
p_asset_list
);
}
if
(
p_key_list
!=
NULL
)
{
vlc_delete_all
(
*
p_key_list
);
delete
(
p_key_list
);
}
}
};
...
...
@@ -117,6 +129,9 @@ public:
virtual
int
Parse
()
=
0
;
static
int
ReadNextNode
(
xml_reader_t
*
p_xmlReader
,
string
&
s_node
);
static
int
ReadEndNode
(
xml_reader_t
*
p_xmlReader
,
string
s_node
,
int
i_type
,
string
&
s_value
);
bool
IsCPL
()
{
return
type
==
XML_CPL
;
}
protected:
demux_t
*
p_demux
;
...
...
@@ -164,6 +179,7 @@ public:
else
this
->
s_annotation
=
this
->
s_annotation
+
"--"
+
p_string
;
};
void
setKeyId
(
string
p_string
)
{
this
->
s_key_id
=
p_string
;
};
void
setPackingList
(
bool
p_bool
)
{
this
->
s_path
=
p_bool
;
};
void
setEntryPoint
(
int
i_val
)
{
this
->
i_entry_point
=
i_val
;
};
void
setDuration
(
int
i_val
)
{
this
->
i_duration
=
i_val
;
};
...
...
@@ -172,6 +188,7 @@ public:
string
getPath
()
const
{
return
this
->
s_path
;
};
string
getType
()
const
{
return
this
->
s_type
;
};
string
getOriginalFilename
()
const
{
return
this
->
s_original_filename
;
};
string
getKeyId
()
const
{
return
this
->
s_key_id
;
}
int
getEntryPoint
()
const
{
return
this
->
i_entry_point
;
};
int
getDuration
()
const
{
return
this
->
i_duration
;
};
int
getIntrinsicDuration
()
const
{
return
this
->
i_intrisic_duration
;
};
...
...
@@ -181,6 +198,8 @@ public:
int
Parse
(
xml_reader_t
*
p_xmlReader
,
string
node
,
int
type
);
int
ParsePKL
(
xml_reader_t
*
p_xmlReader
);
static
AESKey
*
getAESKeyById
(
AESKeyList
*
,
const
string
s_id
);
// TODO: remove
void
Dump
();
...
...
@@ -315,4 +334,76 @@ private:
int
ParseAssetList
(
xml_reader_t
*
p_xmlReader
,
const
string
p_node
,
int
p_type
);
};
class
KDM
:
public
XmlFile
{
public:
KDM
(
demux_t
*
p_demux
,
string
s_path
,
dcp_t
*
_p_dcp
)
:
XmlFile
(
p_demux
,
s_path
),
p_dcp
(
_p_dcp
)
{}
virtual
int
Parse
();
private:
dcp_t
*
p_dcp
;
int
ParsePrivate
(
const
string
s_node
,
int
i_type
);
};
class
AESKey
{
public:
AESKey
(
demux_t
*
demux
)
:
p_demux
(
demux
)
{
}
virtual
~
AESKey
()
{};
const
string
getKeyId
()
{
return
this
->
s_key_id
;
};
const
unsigned
char
*
getKey
()
{
return
this
->
ps_key
;
};
int
Parse
(
xml_reader_t
*
p_xml_reader
,
string
s_node
,
int
i_type
);
private:
demux_t
*
p_demux
;
string
s_key_id
;
unsigned
char
ps_key
[
16
];
int
decryptRSA
(
string
s_cipher_text_b64
);
int
extractInfo
(
unsigned
char
*
ps_plain_text
,
bool
smpte
);
};
class
RSAKey
{
public:
RSAKey
(
demux_t
*
demux
)
:
priv_key
(
NULL
),
p_demux
(
demux
)
{
}
virtual
~
RSAKey
()
{
gcry_sexp_release
(
priv_key
);
}
/* some ASN.1 tags. */
enum
{
TAG_INTEGER
=
2
,
TAG_SEQUENCE
=
16
,
};
/* ASN.1 Parser object. */
struct
tag_info
{
int
class_
;
/* Object class. */
unsigned
long
tag
;
/* The tag of the object. */
unsigned
long
length
;
/* Length of the values. */
int
nhdr
;
/* Length of the header (TL). */
unsigned
int
ndef
:
1
;
/* The object has an indefinite length. */
unsigned
int
cons
:
1
;
/* This is a constructed object. */
};
int
setPath
();
int
readPEM
();
int
readDER
(
unsigned
char
const
*
ps_data_der
,
size_t
length
);
int
parseTag
(
unsigned
char
const
**
buffer
,
size_t
*
buflen
,
struct
tag_info
*
ti
);
gcry_sexp_t
priv_key
;
private:
demux_t
*
p_demux
;
string
s_path
;
};
#endif
/* _DCPPARSER_H */
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