Line data Source code
1 : /*
2 : * Copyright 2013, Mozilla Foundation and contributors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 :
17 : #ifndef GMP_DECRYPTION_h_
18 : #define GMP_DECRYPTION_h_
19 :
20 : #include "gmp-platform.h"
21 :
22 0 : class GMPStringList {
23 : public:
24 : virtual uint32_t Size() const = 0;
25 :
26 : virtual void StringAt(uint32_t aIndex,
27 : const char** aOutString, uint32_t* aOutLength) const = 0;
28 :
29 0 : virtual ~GMPStringList() { }
30 : };
31 :
32 0 : class GMPEncryptedBufferMetadata {
33 : public:
34 : // Key ID to identify the decryption key.
35 : virtual const uint8_t* KeyId() const = 0;
36 :
37 : // Size (in bytes) of |KeyId()|.
38 : virtual uint32_t KeyIdSize() const = 0;
39 :
40 : // Initialization vector.
41 : virtual const uint8_t* IV() const = 0;
42 :
43 : // Size (in bytes) of |IV|.
44 : virtual uint32_t IVSize() const = 0;
45 :
46 : // Number of entries returned by ClearBytes() and CipherBytes().
47 : virtual uint32_t NumSubsamples() const = 0;
48 :
49 : virtual const uint16_t* ClearBytes() const = 0;
50 :
51 : virtual const uint32_t* CipherBytes() const = 0;
52 :
53 0 : virtual ~GMPEncryptedBufferMetadata() {}
54 :
55 : // The set of MediaKeySession IDs associated with this decryption key in
56 : // the current stream.
57 : virtual const GMPStringList* SessionIds() const = 0;
58 : };
59 :
60 0 : class GMPBuffer {
61 : public:
62 : virtual uint32_t Id() const = 0;
63 : virtual uint8_t* Data() = 0;
64 : virtual uint32_t Size() const = 0;
65 : virtual void Resize(uint32_t aSize) = 0;
66 0 : virtual ~GMPBuffer() {}
67 : };
68 :
69 : // These match to the DOMException codes as per:
70 : // http://www.w3.org/TR/dom/#domexception
71 : enum GMPDOMException {
72 : kGMPNoModificationAllowedError = 7,
73 : kGMPNotFoundError = 8,
74 : kGMPNotSupportedError = 9,
75 : kGMPInvalidStateError = 11,
76 : kGMPSyntaxError = 12,
77 : kGMPInvalidModificationError = 13,
78 : kGMPInvalidAccessError = 15,
79 : kGMPSecurityError = 18,
80 : kGMPAbortError = 20,
81 : kGMPQuotaExceededError = 22,
82 : kGMPTimeoutError = 23,
83 : kGMPTypeError = 52
84 : };
85 :
86 : enum GMPSessionMessageType {
87 : kGMPLicenseRequest = 0,
88 : kGMPLicenseRenewal = 1,
89 : kGMPLicenseRelease = 2,
90 : kGMPIndividualizationRequest = 3,
91 : kGMPMessageInvalid = 4 // Must always be last.
92 : };
93 :
94 : enum GMPMediaKeyStatus {
95 : kGMPUsable = 0,
96 : kGMPExpired = 1,
97 : kGMPOutputDownscaled = 2,
98 : kGMPOutputRestricted = 3,
99 : kGMPInternalError = 4,
100 : kGMPUnknown = 5, // Removes key from MediaKeyStatusMap
101 : kGMPReleased = 6,
102 : kGMPStatusPending = 7,
103 : kGMPMediaKeyStatusInvalid = 8 // Must always be last.
104 : };
105 :
106 : struct GMPMediaKeyInfo {
107 : GMPMediaKeyInfo() {}
108 0 : GMPMediaKeyInfo(const uint8_t* aKeyId,
109 : uint32_t aKeyIdSize,
110 : GMPMediaKeyStatus aStatus)
111 0 : : keyid(aKeyId)
112 : , keyid_size(aKeyIdSize)
113 0 : , status(aStatus)
114 0 : {}
115 : const uint8_t* keyid;
116 : uint32_t keyid_size;
117 : GMPMediaKeyStatus status;
118 : };
119 :
120 : // Time in milliseconds, as offset from epoch, 1 Jan 1970.
121 : typedef int64_t GMPTimestamp;
122 :
123 : // Callbacks to be called from the CDM. Threadsafe.
124 0 : class GMPDecryptorCallback {
125 : public:
126 :
127 : // The GMPDecryptor should call this in response to a call to
128 : // GMPDecryptor::CreateSession(). The GMP host calls CreateSession() when
129 : // MediaKeySession.generateRequest() is called by JavaScript.
130 : // After CreateSession() is called, the GMPDecryptor should call
131 : // GMPDecryptorCallback::SetSessionId() to set the sessionId exposed to
132 : // JavaScript on the MediaKeySession on which the generateRequest() was
133 : // called. SetSessionId() must be called before
134 : // GMPDecryptorCallback::SessionMessage() will work.
135 : // aSessionId must be null terminated.
136 : // Note: pass the aCreateSessionToken from the CreateSession() call,
137 : // and then once the session has sent any messages required for the
138 : // license request to be sent, then resolve the aPromiseId that was passed
139 : // to GMPDecryptor::CreateSession().
140 : // Note: GMPDecryptor::LoadSession() does *not* need to call SetSessionId()
141 : // for GMPDecryptorCallback::SessionMessage() to work.
142 : virtual void SetSessionId(uint32_t aCreateSessionToken,
143 : const char* aSessionId,
144 : uint32_t aSessionIdLength) = 0;
145 :
146 : // Resolves a promise for a session loaded.
147 : // Resolves to false if we don't have any session data stored for the given
148 : // session ID.
149 : // Must be called before SessionMessage().
150 : virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
151 : bool aSuccess) = 0;
152 :
153 : // Called to resolve a specified promise with "undefined".
154 : virtual void ResolvePromise(uint32_t aPromiseId) = 0;
155 :
156 : // Called to reject a promise with a DOMException.
157 : // aMessage is logged to the WebConsole.
158 : // aMessage is optional, but if present must be null terminated.
159 : virtual void RejectPromise(uint32_t aPromiseId,
160 : GMPDOMException aException,
161 : const char* aMessage,
162 : uint32_t aMessageLength) = 0;
163 :
164 : // Called by the CDM when it has a message for a session.
165 : // Length parameters should not include null termination.
166 : // aSessionId must be null terminated.
167 : virtual void SessionMessage(const char* aSessionId,
168 : uint32_t aSessionIdLength,
169 : GMPSessionMessageType aMessageType,
170 : const uint8_t* aMessage,
171 : uint32_t aMessageLength) = 0;
172 :
173 : // aSessionId must be null terminated.
174 : virtual void ExpirationChange(const char* aSessionId,
175 : uint32_t aSessionIdLength,
176 : GMPTimestamp aExpiryTime) = 0;
177 :
178 : // Called by the GMP when a session is closed. All file IO
179 : // that a session requires should be complete before calling this.
180 : // aSessionId must be null terminated.
181 : virtual void SessionClosed(const char* aSessionId,
182 : uint32_t aSessionIdLength) = 0;
183 :
184 : // Called by the GMP when an error occurs in a session.
185 : // aSessionId must be null terminated.
186 : // aMessage is logged to the WebConsole.
187 : // aMessage is optional, but if present must be null terminated.
188 : virtual void SessionError(const char* aSessionId,
189 : uint32_t aSessionIdLength,
190 : GMPDOMException aException,
191 : uint32_t aSystemCode,
192 : const char* aMessage,
193 : uint32_t aMessageLength) = 0;
194 :
195 : // Notifies the status of a key. Gecko will not call into the CDM to decrypt
196 : // or decode content encrypted with a key unless the CDM has marked it
197 : // usable first. So a CDM *MUST* mark its usable keys as usable!
198 : virtual void KeyStatusChanged(const char* aSessionId,
199 : uint32_t aSessionIdLength,
200 : const uint8_t* aKeyId,
201 : uint32_t aKeyIdLength,
202 : GMPMediaKeyStatus aStatus) = 0;
203 :
204 : // DEPRECATED; this function has no affect.
205 : virtual void SetCapabilities(uint64_t aCaps) = 0;
206 :
207 : // Returns decrypted buffer to Gecko, or reports failure.
208 : virtual void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) = 0;
209 :
210 : // To aggregate KeyStatusChanged into single callback per session id.
211 : virtual void BatchedKeyStatusChanged(const char* aSessionId,
212 : uint32_t aSessionIdLength,
213 : const GMPMediaKeyInfo* aKeyInfos,
214 : uint32_t aKeyInfosLength) = 0;
215 :
216 0 : virtual ~GMPDecryptorCallback() {}
217 : };
218 :
219 : enum GMPSessionType {
220 : kGMPTemporySession = 0,
221 : kGMPPersistentSession = 1,
222 : kGMPSessionInvalid = 2 // Must always be last.
223 : };
224 :
225 : #define GMP_API_DECRYPTOR "eme-decrypt-v9"
226 :
227 : // API exposed by plugin library to manage decryption sessions.
228 : // When the Host requests this by calling GMPGetAPIFunc().
229 : //
230 : // API name macro: GMP_API_DECRYPTOR
231 0 : class GMPDecryptor {
232 : public:
233 :
234 : // Sets the callback to use with the decryptor to return results
235 : // to Gecko.
236 : virtual void Init(GMPDecryptorCallback* aCallback,
237 : bool aDistinctiveIdentifierRequired,
238 : bool aPersistentStateRequired) = 0;
239 :
240 : // Initiates the creation of a session given |aType| and |aInitData|, and
241 : // the generation of a license request message.
242 : //
243 : // This corresponds to a MediaKeySession.generateRequest() call in JS.
244 : //
245 : // The GMPDecryptor must do the following, in order, upon this method
246 : // being called:
247 : //
248 : // 1. Generate a sessionId to expose to JS, and call
249 : // GMPDecryptorCallback::SetSessionId(aCreateSessionToken, sessionId...)
250 : // with the sessionId to be exposed to JS/EME on the MediaKeySession
251 : // object on which generateRequest() was called, and then
252 : // 2. send any messages to JS/EME required to generate a license request
253 : // given the supplied initData, and then
254 : // 3. generate a license request message, and send it to JS/EME, and then
255 : // 4. call GMPDecryptorCallback::ResolvePromise().
256 : //
257 : // Note: GMPDecryptorCallback::SetSessionId(aCreateSessionToken, sessionId, ...)
258 : // *must* be called before GMPDecryptorCallback::SendMessage(sessionId, ...)
259 : // will work.
260 : //
261 : // If generating the request fails, reject aPromiseId by calling
262 : // GMPDecryptorCallback::RejectPromise().
263 : virtual void CreateSession(uint32_t aCreateSessionToken,
264 : uint32_t aPromiseId,
265 : const char* aInitDataType,
266 : uint32_t aInitDataTypeSize,
267 : const uint8_t* aInitData,
268 : uint32_t aInitDataSize,
269 : GMPSessionType aSessionType) = 0;
270 :
271 : // Loads a previously loaded persistent session.
272 : //
273 : // This corresponds to a MediaKeySession.load() call in JS.
274 : //
275 : // The GMPDecryptor must do the following, in order, upon this method
276 : // being called:
277 : //
278 : // 1. Send any messages to JS/EME, or read from storage, whatever is
279 : // required to load the session, and then
280 : // 2. if there is no session with the given sessionId loadable, call
281 : // ResolveLoadSessionPromise(aPromiseId, false), otherwise
282 : // 2. mark the session's keys as usable, and then
283 : // 3. update the session's expiration, and then
284 : // 4. call GMPDecryptorCallback::ResolveLoadSessionPromise(aPromiseId, true).
285 : //
286 : // If loading the session fails due to error, reject aPromiseId by calling
287 : // GMPDecryptorCallback::RejectPromise().
288 : virtual void LoadSession(uint32_t aPromiseId,
289 : const char* aSessionId,
290 : uint32_t aSessionIdLength) = 0;
291 :
292 : // Updates the session with |aResponse|.
293 : // This corresponds to a MediaKeySession.update() call in JS.
294 : virtual void UpdateSession(uint32_t aPromiseId,
295 : const char* aSessionId,
296 : uint32_t aSessionIdLength,
297 : const uint8_t* aResponse,
298 : uint32_t aResponseSize) = 0;
299 :
300 : // Releases the resources (keys) for the specified session.
301 : // This corresponds to a MediaKeySession.close() call in JS.
302 : virtual void CloseSession(uint32_t aPromiseId,
303 : const char* aSessionId,
304 : uint32_t aSessionIdLength) = 0;
305 :
306 : // Removes the resources (keys) for the specified session.
307 : // This corresponds to a MediaKeySession.remove() call in JS.
308 : virtual void RemoveSession(uint32_t aPromiseId,
309 : const char* aSessionId,
310 : uint32_t aSessionIdLength) = 0;
311 :
312 : // Resolve/reject promise on completion.
313 : // This corresponds to a MediaKeySession.setServerCertificate() call in JS.
314 : virtual void SetServerCertificate(uint32_t aPromiseId,
315 : const uint8_t* aServerCert,
316 : uint32_t aServerCertSize) = 0;
317 :
318 : // Asynchronously decrypts aBuffer in place. When the decryption is
319 : // complete, GMPDecryptor should write the decrypted data back into the
320 : // same GMPBuffer object and return it to Gecko by calling Decrypted(),
321 : // with the GMPNoErr successcode. If decryption fails, call Decrypted()
322 : // with a failure code, and an error event will fire on the media element.
323 : // Note: When Decrypted() is called and aBuffer is passed back, aBuffer
324 : // is deleted. Don't forget to call Decrypted(), as otherwise aBuffer's
325 : // memory will leak!
326 : virtual void Decrypt(GMPBuffer* aBuffer,
327 : GMPEncryptedBufferMetadata* aMetadata) = 0;
328 :
329 : // Called when the decryption operations are complete.
330 : // Do not call the GMPDecryptorCallback's functions after this is called.
331 : virtual void DecryptingComplete() = 0;
332 :
333 0 : virtual ~GMPDecryptor() {}
334 : };
335 :
336 : #endif // GMP_DECRYPTION_h_
|