Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include <opencdm/open_cdm.h>
21 :
22 : #include "ActiveSessions.h"
23 : #include "Logger.h"
24 : #include "MediaKeysCapabilitiesBackend.h"
25 : #include "OpenCDMSession.h"
26 : #include "OpenCDMSystemPrivate.h"
27 : #include <cassert>
28 : #include <cstring>
29 :
30 : namespace
31 : {
32 : const Logger kLog{"open_cdm"};
33 :
34 4 : bool isNetflixPlayreadyKeysystem(const std::string &keySystem)
35 : {
36 4 : return keySystem.find("netflix") != std::string::npos;
37 : }
38 : } // namespace
39 :
40 1 : OpenCDMSystem *opencdm_create_system(const char keySystem[])
41 : {
42 1 : kLog << debug << __func__;
43 :
44 1 : const char kSrcRev[] = SRCREV;
45 1 : const char kTags[] = TAGS;
46 :
47 : if (std::strlen(kSrcRev) > 0)
48 : {
49 : if (std::strlen(kTags) > 0)
50 : {
51 : kLog << mil << "Release Tag(s): " << kTags << " (Commit ID: " << kSrcRev << ")";
52 : }
53 : else
54 : {
55 1 : kLog << mil << "Release Tag(s): No Release Tags!" << " (Commit ID: " << kSrcRev << ")";
56 : }
57 : }
58 : else
59 : {
60 : kLog << warn << "Failed to get git commit ID!";
61 : }
62 :
63 1 : OpenCDMSystem *result = nullptr;
64 1 : opencdm_create_system_extended(keySystem, &result);
65 :
66 1 : return result;
67 : }
68 :
69 1 : OpenCDMError opencdm_create_system_extended(const char keySystem[], struct OpenCDMSystem **system)
70 : {
71 1 : kLog << debug << __func__;
72 1 : assert(system != nullptr);
73 :
74 1 : *system = createSystem(keySystem, "");
75 :
76 1 : return ERROR_NONE;
77 : }
78 :
79 1 : OpenCDMError opencdm_destruct_system(struct OpenCDMSystem *system)
80 : {
81 1 : kLog << debug << __func__;
82 1 : if (system)
83 : {
84 1 : delete system;
85 : }
86 :
87 1 : return ERROR_NONE;
88 : }
89 :
90 1 : OpenCDMError opencdm_is_type_supported(const char keySystem[], const char mimeType[])
91 : {
92 1 : kLog << debug << __func__;
93 3 : return MediaKeysCapabilitiesBackend::instance().supportsKeySystem(std::string(keySystem));
94 : }
95 :
96 3 : OpenCDMError opencdm_system_get_metadata(struct OpenCDMSystem *system, char metadata[], uint16_t *metadataSize)
97 : {
98 3 : kLog << debug << __func__;
99 3 : if (!system || !metadataSize)
100 : {
101 2 : kLog << error << __func__ << ": System or metadataSize is NULL";
102 2 : return ERROR_FAIL;
103 : }
104 1 : *metadataSize = 0;
105 1 : return ERROR_NONE;
106 : }
107 :
108 4 : OpenCDMError opencdm_system_get_version(struct OpenCDMSystem *system, char versionStr[])
109 : {
110 4 : kLog << debug << __func__;
111 4 : if (!system || !versionStr)
112 : {
113 2 : kLog << error << __func__ << ": System or versionStr is NULL";
114 2 : return ERROR_FAIL;
115 : }
116 2 : std::string version;
117 2 : if (!MediaKeysCapabilitiesBackend::instance().getSupportedKeySystemVersion(system->keySystem(), version))
118 : {
119 1 : return ERROR_FAIL;
120 : }
121 :
122 1 : const size_t MAX_LEN = 64;
123 1 : snprintf(versionStr, MAX_LEN, "%s", version.c_str());
124 :
125 1 : return ERROR_NONE;
126 2 : }
127 :
128 4 : OpenCDMError opencdm_system_get_drm_time(struct OpenCDMSystem *system, uint64_t *time)
129 : {
130 4 : kLog << debug << __func__;
131 4 : if (!time || !system)
132 : {
133 2 : kLog << error << "Ptr is null";
134 2 : return ERROR_FAIL;
135 : }
136 2 : if (!system->getDrmTime(*time))
137 : {
138 1 : kLog << error << "Failed to get DRM Time";
139 1 : return ERROR_FAIL;
140 : }
141 1 : return ERROR_NONE;
142 : }
143 :
144 2 : struct OpenCDMSession *opencdm_get_system_session(struct OpenCDMSystem *system, const uint8_t keyId[],
145 : const uint8_t length, const uint32_t waitTime)
146 : {
147 2 : kLog << debug << __func__;
148 6 : return ActiveSessions::instance().get(std::vector<uint8_t>(keyId, keyId + length));
149 : }
150 :
151 1 : OpenCDMError opencdm_system_set_server_certificate(struct OpenCDMSystem *system, const uint8_t serverCertificate[],
152 : const uint16_t serverCertificateLength)
153 : {
154 1 : kLog << debug << __func__;
155 1 : return ERROR_NONE;
156 : }
157 :
158 1 : struct OpenCDMSession *opencdm_get_session(const uint8_t keyId[], const uint8_t length, const uint32_t waitTime)
159 : {
160 1 : kLog << debug << __func__;
161 1 : return opencdm_get_system_session(nullptr, keyId, length, waitTime);
162 : }
163 :
164 6 : OpenCDMError opencdm_construct_session(struct OpenCDMSystem *system, const LicenseType licenseType,
165 : const char initDataType[], const uint8_t initData[],
166 : const uint16_t initDataLength, const uint8_t CDMData[],
167 : const uint16_t CDMDataLength, OpenCDMSessionCallbacks *callbacks, void *userData,
168 : struct OpenCDMSession **session)
169 : {
170 6 : kLog << debug << __func__;
171 6 : if (!system)
172 : {
173 1 : kLog << error << "System is NULL or not initialized";
174 1 : return ERROR_FAIL;
175 : }
176 10 : std::string initializationDataType(initDataType);
177 : std::vector<uint8_t> initDataVec(reinterpret_cast<const uint8_t *>(initData),
178 5 : reinterpret_cast<const uint8_t *>(initData) + initDataLength);
179 :
180 : OpenCDMSession *newSession =
181 5 : system->createSession(licenseType, callbacks, userData, initializationDataType, initDataVec);
182 :
183 5 : if (!newSession)
184 : {
185 1 : return ERROR_INVALID_SESSION;
186 : }
187 :
188 4 : if (!isNetflixPlayreadyKeysystem(system->keySystem()))
189 : {
190 3 : if (!newSession->initialize())
191 : {
192 1 : kLog << error << "Failed to create session";
193 1 : ActiveSessions::instance().remove(newSession);
194 2 : return ERROR_FAIL;
195 : }
196 : std::vector<uint8_t> cdmDataVec(reinterpret_cast<const uint8_t *>(CDMData),
197 2 : reinterpret_cast<const uint8_t *>(CDMData) + CDMDataLength);
198 :
199 2 : if (!newSession->generateRequest(initializationDataType, initDataVec, cdmDataVec /*not used yet*/))
200 : {
201 1 : kLog << error << "Failed to generate request";
202 :
203 1 : opencdm_session_close(newSession);
204 1 : opencdm_destruct_session(newSession);
205 1 : return ERROR_FAIL;
206 : }
207 2 : }
208 :
209 2 : *session = newSession;
210 :
211 2 : return ERROR_NONE;
212 5 : }
213 :
214 3 : OpenCDMError opencdm_destruct_session(struct OpenCDMSession *session)
215 : {
216 3 : kLog << debug << __func__;
217 3 : if (session)
218 : {
219 2 : ActiveSessions::instance().remove(session);
220 2 : return ERROR_NONE;
221 : }
222 1 : return ERROR_INVALID_SESSION;
223 : }
224 :
225 3 : OpenCDMError opencdm_session_load(struct OpenCDMSession *session)
226 : {
227 3 : kLog << debug << __func__;
228 3 : OpenCDMError result = ERROR_INVALID_SESSION;
229 3 : if (session)
230 : {
231 2 : if (session->loadSession())
232 : {
233 1 : result = ERROR_NONE;
234 : }
235 : else
236 : {
237 1 : kLog << error << "Failed to load the session";
238 1 : result = ERROR_FAIL;
239 : }
240 : }
241 :
242 3 : return result;
243 : }
244 :
245 3 : OpenCDMError opencdm_session_metadata(const struct OpenCDMSession *session, char metadata[], uint16_t *metadataSize)
246 : {
247 3 : kLog << debug << __func__;
248 3 : if (!session || !metadataSize)
249 : {
250 2 : kLog << error << __func__ << ": session or metadata size is null";
251 2 : return ERROR_FAIL;
252 : }
253 1 : *metadataSize = 0;
254 1 : return ERROR_NONE;
255 : }
256 :
257 2 : const char *opencdm_session_id(const struct OpenCDMSession *session)
258 : {
259 2 : kLog << debug << __func__;
260 2 : if (!session)
261 : {
262 1 : return nullptr;
263 : }
264 1 : return session->getSessionId().c_str();
265 : }
266 :
267 1 : const char *opencdm_session_buffer_id(const struct OpenCDMSession *session)
268 : {
269 1 : kLog << debug << __func__;
270 1 : return nullptr;
271 : }
272 :
273 2 : uint32_t opencdm_session_has_key_id(struct OpenCDMSession *session, const uint8_t length, const uint8_t keyId[])
274 : {
275 2 : kLog << debug << __func__;
276 2 : if (!session)
277 : {
278 1 : kLog << error << "Failed to check key id";
279 1 : return 0;
280 : }
281 1 : std::vector<uint8_t> key(keyId, keyId + length);
282 1 : return static_cast<uint32_t>(session->containsKey(key));
283 : }
284 :
285 3 : KeyStatus opencdm_session_status(const struct OpenCDMSession *session, const uint8_t keyId[], uint8_t length)
286 : {
287 3 : kLog << debug << __func__;
288 3 : if (session && keyId && 0 != length)
289 : {
290 1 : std::vector<uint8_t> key(keyId, keyId + length);
291 1 : return session->status(key);
292 : }
293 :
294 2 : return InternalError;
295 : }
296 :
297 1 : uint32_t opencdm_session_error(const struct OpenCDMSession *session, const uint8_t keyId[], uint8_t length)
298 : {
299 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
300 1 : return 0;
301 : }
302 :
303 2 : OpenCDMError opencdm_session_system_error(const struct OpenCDMSession *session)
304 : {
305 2 : kLog << debug << __func__;
306 2 : if (!session)
307 : {
308 1 : kLog << error << __func__ << ": Failed to get session system error - session is null";
309 1 : return ERROR_FAIL;
310 : }
311 1 : uint32_t err = session->getLastDrmError();
312 : // Rialto doesn't implement it yet
313 : switch (err)
314 : {
315 : default:
316 1 : return ERROR_NONE;
317 : }
318 : }
319 :
320 4 : OpenCDMError opencdm_session_update(struct OpenCDMSession *session, const uint8_t keyMessage[], uint16_t keyLength)
321 : {
322 4 : kLog << debug << __func__;
323 4 : if (!session)
324 : {
325 1 : kLog << error << __func__ << ": Session is NULL";
326 1 : return ERROR_INVALID_SESSION;
327 : }
328 3 : if (!keyMessage || keyLength == 0)
329 : {
330 1 : kLog << error << __func__ << ": keyMessage is empty";
331 1 : return ERROR_FAIL;
332 : }
333 2 : std::vector<uint8_t> license(keyMessage, keyMessage + keyLength);
334 2 : if (!session->updateSession(license))
335 : {
336 1 : kLog << error << "Failed to update the session";
337 1 : return ERROR_FAIL;
338 : }
339 :
340 1 : return ERROR_NONE;
341 2 : }
342 :
343 3 : OpenCDMError opencdm_session_remove(struct OpenCDMSession *session)
344 : {
345 3 : kLog << debug << __func__;
346 3 : OpenCDMError result = ERROR_INVALID_SESSION;
347 3 : if (session)
348 : {
349 2 : if (session->removeSession())
350 : {
351 1 : result = ERROR_NONE;
352 : }
353 : else
354 : {
355 1 : kLog << error << "Failed to remove the key session";
356 1 : result = ERROR_FAIL;
357 : }
358 : }
359 :
360 3 : return result;
361 : }
362 :
363 1 : OpenCDMError opencdm_session_resetoutputprotection(struct OpenCDMSession *session)
364 : {
365 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
366 1 : return ERROR_NONE;
367 : }
368 :
369 1 : OpenCDMError opencdm_session_set_parameter(struct OpenCDMSession *session, const std::string &name,
370 : const std::string &value)
371 : {
372 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
373 1 : return ERROR_NONE;
374 : }
375 :
376 4 : OpenCDMError opencdm_session_close(struct OpenCDMSession *session)
377 : {
378 4 : kLog << debug << __func__;
379 4 : OpenCDMError result = ERROR_INVALID_SESSION;
380 4 : if (session)
381 : {
382 3 : if (session->closeSession())
383 : {
384 2 : result = ERROR_NONE;
385 : }
386 : else
387 : {
388 1 : kLog << error << "Failed to close the key session";
389 1 : result = ERROR_FAIL;
390 : }
391 : }
392 :
393 4 : return result;
394 : }
395 :
396 2 : OpenCDMBool opencdm_system_supports_server_certificate(struct OpenCDMSystem *system)
397 : {
398 2 : kLog << debug << __func__;
399 2 : if (MediaKeysCapabilitiesBackend::instance().isServerCertificateSupported(system->keySystem()))
400 : {
401 1 : return OpenCDMBool::OPENCDM_BOOL_TRUE;
402 : }
403 1 : return OpenCDMBool::OPENCDM_BOOL_FALSE;
404 : }
405 :
406 1 : OpenCDMError opencdm_session_decrypt(struct OpenCDMSession *session, uint8_t encrypted[],
407 : const uint32_t encryptedLength, const EncryptionScheme encScheme,
408 : const EncryptionPattern pattern, const uint8_t *IV, uint16_t IVLength,
409 : const uint8_t *keyId, const uint16_t keyIdLength, uint32_t initWithLast15)
410 : {
411 1 : kLog << warn << __func__ << " not implemented";
412 1 : return ERROR_FAIL;
413 : }
414 :
415 6 : OpenCDMError opencdm_get_metric_system_data(struct OpenCDMSystem *system, uint32_t *bufferLength, uint8_t *buffer)
416 : {
417 6 : kLog << debug << __func__;
418 6 : if (!system)
419 : {
420 1 : kLog << error << "System ptr is null";
421 1 : return ERROR_FAIL;
422 : }
423 :
424 5 : if (!bufferLength)
425 : {
426 1 : kLog << error << "Buffer length ptr is null";
427 1 : return ERROR_FAIL;
428 : }
429 :
430 4 : if (!buffer)
431 : {
432 1 : kLog << error << "Buffer ptr is null";
433 1 : return ERROR_FAIL;
434 : }
435 :
436 3 : std::vector<uint8_t> bufferVec;
437 3 : if (!system->getMetricSystemData(bufferVec))
438 : {
439 1 : kLog << error << "Failed to get metric system data";
440 1 : return ERROR_FAIL;
441 : }
442 :
443 2 : if (*bufferLength < bufferVec.size())
444 : {
445 2 : kLog << error << "Buffer is too small - return size " << bufferVec.size() << " does not fit in buffer of size "
446 1 : << *bufferLength;
447 1 : return ERROR_BUFFER_TOO_SMALL;
448 : }
449 :
450 1 : std::memcpy(buffer, bufferVec.data(), bufferVec.size());
451 1 : *bufferLength = bufferVec.size();
452 1 : return ERROR_NONE;
453 3 : }
|