One possible security model for video stream access is to use the same SSL mutual authentication technique that we recommend for accessing feeds. (Other models might be randomized expiring URLs with just server side SSL encryption, or some sort of DRM). This post will cover the SSL mutual authentication technique using Apache along with the details of using openssl to generate some test certificates and use them to configure apache on the server side where your video may be stored. Finally, we will modify the simplevideoplayer example to play this secure video.
Create a Self-Signed CA (Certificate Authority) root Certificate
a) Create the CA private key (remember the password chosen):
sudo openssl genrsa -out /opt/openssl/testCA/CA/testCA.KEY
b) Create CA Certificate Request:
sudo openssl req -new -key /opt/openssl/testCA/CA/testCA.KEY -out /opt/openssl/testCA/CA/testCA.CSR
c) Self-sign the CA certificate:
sudo openssl x509 -req -days 3650 -in /opt/openssl/testCA/CA/testCA.CSR -out /opt/openssl/testCA/CA/testCA.CRT -signkey /opt/openssl/testCA/CA/testCA.KEY
OpenSSL Server Cert
a) Create the Web Server’s key (remember the password chosen):
sudo openssl genrsa -des3 -out /opt/openssl/testCA/server/keys/testWEB.KEY
b) Create the Web Server’s Cert Req:
sudo openssl req -new -key /opt/openssl/testCA/server/keys/testWEB.KEY -out /opt/openssl/testCA/server/requests/testWEB.CSR
c) Sign the Web Server’s Cert Req with the CA Cert:
sudo openssl ca -in /opt/openssl/testCA/server/requests/testWEB.CSR -cert /opt/openssl/testCA/CA/testCA.CRT -keyfile /opt/openssl/testCA/CA/testCA.KEY
-out /opt/openssl/testCA/server/certificates/testWEB.CRT
Install Cert in Apache
a) sudo mkdir /etc/httpd/certs
b) sudo cp /opt/openssl/testCA/server/certificates/testWEB.CRT /etc/httpd/certs
c) sudo cp /opt/openssl/testCA/server/keys/testWEB.KEY /etc/httpd/certs
d) sudo cp sudo cp /opt/openssl/testCA/CA/testCA.CRT /etc/httpd/certs
e) If you don’t want to enter the passwd for testWEB every time Apache starts,
you can remove the passwd from the keyfile:
sudo cp /etc/httpd/certs/testWEB.KEY /etc/httpd/certs/testWEB.KEY.orig
sudo openssl rsa -in /etc/httpd/certs/testWEB.KEY.orig -out /etc/httpd/certs/testWEB.KEY
f) Edit /etc/httpd/conf.d/ssl.conf
SSLCACertificateFile /etc/httpd/certs/cacert.pem # from roku sdk
SSLVerifyClient require
SSLVerifyDepth 1
g) Edit /etc/httpd/conf/httpd.conf:
In tags where your video resides:
Checking the x-roku-reserved-dev-id header value assures that it is
your package trying to connect to this directory.
You can find the dev-id of your brightscript package by going to the
developer page on your Roku box, and selecting “Utilities”.
On the “Utilities” page, select “Choose File”, enter the passwd for that pkg, and hit “Inspect”
Copy the value for the “Dev ID:” parameter and paste it here:
SetEnvIf x-roku-reserved-dev-id 6bb22ba64125f6da56fa4b7d6f2199a970d06672 let_roku_in
SSLRequireSSL
Order Deny,Allow
Deny from all
Allow from env=let_roku_in
h) Restart Apache:
sudo service httpd restart
Place your video in your Apache directory configured in step 3.g) above.
Modify the simplevideoplayer application to access the secure video:
a) Add the testCA.CRT (The Certificate Authority cert) file to the
implevideoplayer/source directory.
b) In the appMain.brs:displyVideo() function, change the URL and video meta-data
to match the video you put on your server in step 4).
c) Right before the “video.SetContent(videoclip)” line, add the following calls:
video.Addheader(“x-roku-reserved-dev-id”,“”)
video.SetCertificatesFile(“pkg:/source/testCA.CRT”)
video.InitClientCertificates()
Test the authentication with and without the code in 5.c) above. If any of the three authentication methods above are ommitted you should get access denied. Note that you cannot successfully access the video until you’ve built a package, uploaded it to the channel store, and are running that channel via a channel code. A side-loaded developer app does not properly negotiate client certs or send the enforced dev-id value for the x-roku-reserved-dev-id header.
Any plans of adding DRM support? Or a piracy protection mechanism that is widely approved by film distributors so we can create a distribution channel for our clients?
Trying to follow this example but I can’t get the streams to play over https even without requiring authentication.
The video plays in a browser just fine (albeit with an untrusted cert warning)
But when I try to connect to the https stream from the roku, it just goes back to the detail screen & nothing appears in the web server logs at all.
This is the debug output from roku:
Button pressed: 1 0
Displaying video:
srt = <UNINITIALIZED>
play failed: An unexpected problem (but not server timeout or HTTP error) has been detected.
Closing video screen
Should the video be able to play over https; does the cert need to be signed by a trusted authority?
thank you in advance,
joe
For cacert.pem I tried using just my ca.crt and also tried adding my ca.crt to the pre-existing cacert.pem that came with SDK. Both gave the same result: no video and debug says “play failed: An unexpected problem (but not server timeout or HTTP error) has been detected.”
I’ve tried publishing as a private channel and sideloading to see if i can get a video to play over https (in another thread you said it was possible to play sideloaded channels over https, but maybe i’m confused, because I can’t get it to work). no luck.
Self signed certs are OK with Roku, as long as they are in your PEM file registered with SetCertificatesFile() . After clicking through the warning about “unrecognized CA Cert” of similar warning, are you able to make an SSL connection with your browser?
After clicking through the warning about “unrecognized CA Cert” of similar warning, are you able to make an SSL connection with your browser?
yes, the video plays in a browser just fine (albeit with an untrusted cert warning - ie, in chrome i see “https” with a red line through it and when i click on the lock i see that “Your connection is encrypted with 256-bit encryption” and “The identity of this website has not been verified”)
For roku to connect to https, does the common name need to match? in other words my cert might have the CN as ‘secure.mydomain.com’ but then I access for testing via https://192.168.1.20 In the browser there is a warning but it still allows the connection.
OK I started from the top, create the self-signed cert and server keys with my common name on a test domain pointed to my LAN ip, test in the browser & the video plays on the https common name link, still with the same warning “The identity of this website has not been verified”.
I followed everything exactly through step 3f and left the “VerifyClient require” & “VerifyDepth” commented out of my conf file.
When I try to access the video hosted on the common name link with the simplevideoplayer app I got the same result from roku:
“play failed: An unexpected problem (but not server timeout or HTTP error) has been detected.”
EDIT: I forgot to update my package ‘video.SetCertificatesFile()’ with the new keys from this new time around - i did that and it worked this time!
So (theoretically at least) it was failing the first time because of common name mismatch; and the 2nd time I just needed to update the keys - now I need to see if I get the actual security part to work…
Thanks very much for your patience helping me with this Kevin!
Hi Kevin -
Can the BIF files be served using this same authentication method?
I think that the answer is “No” from reading over here viewtopic.php?f=34&t=26258&p=161913&hilit=bif+auth#p161913
but I wanted to ask in case I’m misunderstanding your answer - it sure would be more convenient to serve everything from the same place!
Another question about the SSL Mutual Auth - do you know if this can be used with the streaming sever behind a proxy?
Ideally we’d like to have the content hosted on a server with only a LAN ip but so far I haven’t been able to get it to work. I tried setting it up so that the proxy would handle the Auth and rewrite the request to an unprotected (HTTP, not S) stream on the LAN but I’m back to square 1 (video won’t play).
Would I need the Auth happening on both the proxy and the backend streaming server?
thank you in advance for any advice or suggestion,
Joe
Hi,
I have been trying to setup the mutual authentication security model as explained in the first post. But I am running into some https issues.
I did the changes to the simpleVideoPlayer Application as suggested by Kevin (SetCertificatesFile(“common:/certs/ca-bundle.crt”) and InitClientCertificates()).
When I try to play the video, I get the following error - “play failed: An unexpected problem (but not server timeout or HTTP error) has been detected.”
If I add roSystemLog to the video player, the message status indicates - “UntrustedCert”
The certificate that is installed in my webserver/apache is proper purchased certificate. But, it is a wild-card certificate – CommonName is *.mywebsite.com. Could wild-card be the problem?
But, when we use the roUrlTransfer directly for fetching the feed urls from the same server, https goes through fine. Is there any difference in the way https gets handled in roUrlTransfer and roVideoScreen?
From our experimentation, it seems that you cannot set your own client certificate on the Roku. All Roku’s use the same “RokuClient” certificate. We had to load the RokuCA on the server so that we could validate the RokuClient certificate.
The consequences of this are that all Roku apps use the same client cert. This means another companies Roku apps could establish an SSL connection to our services. This doesn’t provide very much security.
Each Roku has it’s own unique client cert. All the client certs are signed by the RokuCA.
You are correct that the client cert does not protect you against another company’s Roku app establishing an SSL connection to your services. That protection is provided by the authoritative x-roku-reserved-dev-id header. If your web server is checking the value of this devid header, then only applications signed by your key can establish an SSL connection to your services.
This header cannot be forged as the firmware enforces its value. You must implement all pieces of this SSL mutual authentication with devid header to establish encrypted, authorized, secure SSL connections to your services.
Checking the x-roku-reserved-dev-id header value assures that it is
your package trying to connect to this directory.
#
You can find the dev-id of your brightscript package by going to the
developer page on your Roku box, and selecting “Utilities”.
On the “Utilities” page, select “Choose File”, enter the passwd for that pkg, and hit “Inspect”
Copy the value for the “Dev ID:” parameter and paste it here:
SetEnvIf x-roku-reserved-dev-id 6bb22ba64125f6da56fa4b7d6f2199a970d06672 let_roku_in
SSLRequireSSL
Order Deny,Allow
Deny from all
Allow from env=let_roku_in