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 <cstdlib>
29 : #include <cstring>
30 : #include <limits>
31 :
32 : namespace
33 : {
34 : const Logger kLog{"open_cdm"};
35 : } // namespace
36 :
37 1 : OpenCDMSystem *opencdm_create_system(const char keySystem[])
38 : {
39 1 : kLog << debug << __func__;
40 :
41 1 : const char kSrcRev[] = SRCREV;
42 1 : const char kTags[] = TAGS;
43 :
44 : if (std::strlen(kSrcRev) > 0)
45 : {
46 : if (std::strlen(kTags) > 0)
47 : {
48 : kLog << mil << "Release Tag(s): " << kTags << " (Commit ID: " << kSrcRev << ")";
49 : }
50 : else
51 : {
52 1 : kLog << mil << "Release Tag(s): No Release Tags!" << " (Commit ID: " << kSrcRev << ")";
53 : }
54 : }
55 : else
56 : {
57 : kLog << warn << "Failed to get git commit ID!";
58 : }
59 :
60 1 : OpenCDMSystem *result = nullptr;
61 1 : opencdm_create_system_extended(keySystem, &result);
62 :
63 1 : return result;
64 : }
65 :
66 1 : OpenCDMError opencdm_create_system_extended(const char keySystem[], struct OpenCDMSystem **system)
67 : {
68 1 : kLog << debug << __func__;
69 1 : assert(system != nullptr);
70 :
71 1 : *system = createSystem(keySystem, "");
72 :
73 1 : return ERROR_NONE;
74 : }
75 :
76 1 : OpenCDMError opencdm_destruct_system(struct OpenCDMSystem *system)
77 : {
78 1 : kLog << debug << __func__;
79 1 : if (system)
80 : {
81 1 : delete system;
82 : }
83 :
84 1 : return ERROR_NONE;
85 : }
86 :
87 7 : OpenCDMError opencdm_system_supported_robustness(struct OpenCDMSystem *system, char ***robustness, uint16_t *count)
88 : {
89 7 : kLog << debug << __func__;
90 7 : if (!system || !robustness || !count)
91 : {
92 3 : kLog << error << __func__ << ": system, robustness or count is NULL";
93 3 : return ERROR_FAIL;
94 : }
95 :
96 4 : *robustness = nullptr;
97 4 : *count = 0;
98 :
99 4 : std::vector<std::string> levels;
100 4 : if (!MediaKeysCapabilitiesBackend::instance().getSupportedRobustnessLevels(system->keySystem(), levels))
101 : {
102 1 : kLog << warn << __func__ << ": getSupportedRobustnessLevels failed";
103 1 : return ERROR_FAIL;
104 : }
105 :
106 3 : if (levels.empty())
107 : {
108 1 : return ERROR_NONE;
109 : }
110 :
111 2 : if (levels.size() > std::numeric_limits<uint16_t>::max())
112 : {
113 1 : kLog << error << __func__ << ": robustness level count exceeds uint16_t range";
114 1 : return ERROR_FAIL;
115 : }
116 :
117 1 : char **results = static_cast<char **>(calloc(levels.size(), sizeof(char *)));
118 : if (!results) // LCOV_EXCL_START
119 : {
120 : kLog << error << __func__ << ": failed to allocate robustness buffer";
121 : return ERROR_FAIL;
122 : } // LCOV_EXCL_STOP
123 :
124 3 : for (size_t i = 0; i < levels.size(); ++i)
125 : {
126 2 : results[i] = strdup(levels[i].c_str());
127 : if (!results[i]) // LCOV_EXCL_START
128 : {
129 : kLog << error << __func__ << ": failed to allocate robustness level string";
130 : for (size_t j = 0; j < i; ++j)
131 : {
132 : free(results[j]);
133 : }
134 : free(results);
135 : return ERROR_FAIL;
136 : } // LCOV_EXCL_STOP
137 : }
138 :
139 1 : *robustness = results;
140 1 : *count = static_cast<uint16_t>(levels.size());
141 1 : return ERROR_NONE;
142 4 : }
143 :
144 1 : OpenCDMError opencdm_is_type_supported(const char keySystem[], const char mimeType[])
145 : {
146 1 : kLog << debug << __func__;
147 3 : return MediaKeysCapabilitiesBackend::instance().supportsKeySystem(std::string(keySystem));
148 : }
149 :
150 3 : OpenCDMError opencdm_system_get_metadata(struct OpenCDMSystem *system, char metadata[], uint16_t *metadataSize)
151 : {
152 3 : kLog << debug << __func__;
153 3 : if (!system || !metadataSize)
154 : {
155 2 : kLog << error << __func__ << ": System or metadataSize is NULL";
156 2 : return ERROR_FAIL;
157 : }
158 1 : *metadataSize = 0;
159 1 : return ERROR_NONE;
160 : }
161 :
162 4 : OpenCDMError opencdm_system_get_version(struct OpenCDMSystem *system, char versionStr[])
163 : {
164 4 : kLog << debug << __func__;
165 4 : if (!system || !versionStr)
166 : {
167 2 : kLog << error << __func__ << ": System or versionStr is NULL";
168 2 : return ERROR_FAIL;
169 : }
170 2 : std::string version;
171 2 : if (!MediaKeysCapabilitiesBackend::instance().getSupportedKeySystemVersion(system->keySystem(), version))
172 : {
173 1 : return ERROR_FAIL;
174 : }
175 :
176 1 : const size_t MAX_LEN = 64;
177 1 : snprintf(versionStr, MAX_LEN, "%s", version.c_str());
178 :
179 1 : return ERROR_NONE;
180 2 : }
181 :
182 4 : OpenCDMError opencdm_system_get_drm_time(struct OpenCDMSystem *system, uint64_t *time)
183 : {
184 4 : kLog << debug << __func__;
185 4 : if (!time || !system)
186 : {
187 2 : kLog << error << "Ptr is null";
188 2 : return ERROR_FAIL;
189 : }
190 2 : if (!system->getDrmTime(*time))
191 : {
192 1 : kLog << error << "Failed to get DRM Time";
193 1 : return ERROR_FAIL;
194 : }
195 1 : return ERROR_NONE;
196 : }
197 :
198 2 : struct OpenCDMSession *opencdm_get_system_session(struct OpenCDMSystem *system, const uint8_t keyId[],
199 : const uint8_t length, const uint32_t waitTime)
200 : {
201 2 : kLog << debug << __func__;
202 6 : return ActiveSessions::instance().get(std::vector<uint8_t>(keyId, keyId + length));
203 : }
204 :
205 1 : OpenCDMError opencdm_system_set_server_certificate(struct OpenCDMSystem *system, const uint8_t serverCertificate[],
206 : const uint16_t serverCertificateLength)
207 : {
208 1 : kLog << debug << __func__;
209 1 : return ERROR_NONE;
210 : }
211 :
212 1 : struct OpenCDMSession *opencdm_get_session(const uint8_t keyId[], const uint8_t length, const uint32_t waitTime)
213 : {
214 1 : kLog << debug << __func__;
215 1 : return opencdm_get_system_session(nullptr, keyId, length, waitTime);
216 : }
217 :
218 5 : OpenCDMError opencdm_construct_session(struct OpenCDMSystem *system, const LicenseType licenseType,
219 : const char initDataType[], const uint8_t initData[],
220 : const uint16_t initDataLength, const uint8_t CDMData[],
221 : const uint16_t CDMDataLength, OpenCDMSessionCallbacks *callbacks, void *userData,
222 : struct OpenCDMSession **session)
223 : {
224 5 : kLog << debug << __func__;
225 5 : if (!system)
226 : {
227 1 : kLog << error << "System is NULL or not initialized";
228 1 : return ERROR_FAIL;
229 : }
230 8 : std::string initializationDataType(initDataType);
231 : std::vector<uint8_t> initDataVec(reinterpret_cast<const uint8_t *>(initData),
232 4 : reinterpret_cast<const uint8_t *>(initData) + initDataLength);
233 :
234 : OpenCDMSession *newSession =
235 4 : system->createSession(licenseType, callbacks, userData, initializationDataType, initDataVec);
236 :
237 4 : if (!newSession)
238 : {
239 1 : return ERROR_INVALID_SESSION;
240 : }
241 :
242 3 : if (!newSession->initialize())
243 : {
244 1 : kLog << error << "Failed to create session";
245 1 : ActiveSessions::instance().remove(newSession);
246 1 : return ERROR_FAIL;
247 : }
248 : std::vector<uint8_t> cdmDataVec(reinterpret_cast<const uint8_t *>(CDMData),
249 2 : reinterpret_cast<const uint8_t *>(CDMData) + CDMDataLength);
250 :
251 2 : if (!newSession->generateRequest(initializationDataType, initDataVec, cdmDataVec /*not used yet*/))
252 : {
253 1 : kLog << error << "Failed to generate request";
254 :
255 1 : opencdm_session_close(newSession);
256 1 : opencdm_destruct_session(newSession);
257 1 : return ERROR_FAIL;
258 : }
259 :
260 1 : *session = newSession;
261 :
262 1 : return ERROR_NONE;
263 4 : }
264 :
265 3 : OpenCDMError opencdm_destruct_session(struct OpenCDMSession *session)
266 : {
267 3 : kLog << debug << __func__;
268 3 : if (session)
269 : {
270 2 : ActiveSessions::instance().remove(session);
271 2 : return ERROR_NONE;
272 : }
273 1 : return ERROR_INVALID_SESSION;
274 : }
275 :
276 3 : OpenCDMError opencdm_session_load(struct OpenCDMSession *session)
277 : {
278 3 : kLog << debug << __func__;
279 3 : OpenCDMError result = ERROR_INVALID_SESSION;
280 3 : if (session)
281 : {
282 2 : if (session->loadSession())
283 : {
284 1 : result = ERROR_NONE;
285 : }
286 : else
287 : {
288 1 : kLog << error << "Failed to load the session";
289 1 : result = ERROR_FAIL;
290 : }
291 : }
292 :
293 3 : return result;
294 : }
295 :
296 3 : OpenCDMError opencdm_session_metadata(const struct OpenCDMSession *session, char metadata[], uint16_t *metadataSize)
297 : {
298 3 : kLog << debug << __func__;
299 3 : if (!session || !metadataSize)
300 : {
301 2 : kLog << error << __func__ << ": session or metadata size is null";
302 2 : return ERROR_FAIL;
303 : }
304 1 : *metadataSize = 0;
305 1 : return ERROR_NONE;
306 : }
307 :
308 2 : const char *opencdm_session_id(const struct OpenCDMSession *session)
309 : {
310 2 : kLog << debug << __func__;
311 2 : if (!session)
312 : {
313 1 : return nullptr;
314 : }
315 1 : return session->getSessionId().c_str();
316 : }
317 :
318 1 : const char *opencdm_session_buffer_id(const struct OpenCDMSession *session)
319 : {
320 1 : kLog << debug << __func__;
321 1 : return nullptr;
322 : }
323 :
324 2 : uint32_t opencdm_session_has_key_id(struct OpenCDMSession *session, const uint8_t length, const uint8_t keyId[])
325 : {
326 2 : kLog << debug << __func__;
327 2 : if (!session)
328 : {
329 1 : kLog << error << "Failed to check key id";
330 1 : return 0;
331 : }
332 1 : std::vector<uint8_t> key(keyId, keyId + length);
333 1 : return static_cast<uint32_t>(session->containsKey(key));
334 : }
335 :
336 3 : KeyStatus opencdm_session_status(const struct OpenCDMSession *session, const uint8_t keyId[], uint8_t length)
337 : {
338 3 : kLog << debug << __func__;
339 3 : if (session && keyId && 0 != length)
340 : {
341 1 : std::vector<uint8_t> key(keyId, keyId + length);
342 1 : return session->status(key);
343 : }
344 :
345 2 : return InternalError;
346 : }
347 :
348 1 : uint32_t opencdm_session_error(const struct OpenCDMSession *session, const uint8_t keyId[], uint8_t length)
349 : {
350 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
351 1 : return 0;
352 : }
353 :
354 2 : OpenCDMError opencdm_session_system_error(const struct OpenCDMSession *session)
355 : {
356 2 : kLog << debug << __func__;
357 2 : if (!session)
358 : {
359 1 : kLog << error << __func__ << ": Failed to get session system error - session is null";
360 1 : return ERROR_FAIL;
361 : }
362 1 : uint32_t err = session->getLastDrmError();
363 : // Rialto doesn't implement it yet
364 : switch (err)
365 : {
366 : default:
367 1 : return ERROR_NONE;
368 : }
369 : }
370 :
371 4 : OpenCDMError opencdm_session_update(struct OpenCDMSession *session, const uint8_t keyMessage[], uint16_t keyLength)
372 : {
373 4 : kLog << debug << __func__;
374 4 : if (!session)
375 : {
376 1 : kLog << error << __func__ << ": Session is NULL";
377 1 : return ERROR_INVALID_SESSION;
378 : }
379 3 : if (!keyMessage || keyLength == 0)
380 : {
381 1 : kLog << error << __func__ << ": keyMessage is empty";
382 1 : return ERROR_FAIL;
383 : }
384 2 : std::vector<uint8_t> license(keyMessage, keyMessage + keyLength);
385 2 : if (!session->updateSession(license))
386 : {
387 1 : kLog << error << "Failed to update the session";
388 1 : return ERROR_FAIL;
389 : }
390 :
391 1 : return ERROR_NONE;
392 2 : }
393 :
394 3 : OpenCDMError opencdm_session_remove(struct OpenCDMSession *session)
395 : {
396 3 : kLog << debug << __func__;
397 3 : OpenCDMError result = ERROR_INVALID_SESSION;
398 3 : if (session)
399 : {
400 2 : if (session->removeSession())
401 : {
402 1 : result = ERROR_NONE;
403 : }
404 : else
405 : {
406 1 : kLog << error << "Failed to remove the key session";
407 1 : result = ERROR_FAIL;
408 : }
409 : }
410 :
411 3 : return result;
412 : }
413 :
414 1 : OpenCDMError opencdm_session_resetoutputprotection(struct OpenCDMSession *session)
415 : {
416 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
417 1 : return ERROR_NONE;
418 : }
419 :
420 1 : OpenCDMError opencdm_session_set_parameter(struct OpenCDMSession *session, const std::string &name,
421 : const std::string &value)
422 : {
423 1 : kLog << warn << __func__ << " NOT IMPLEMENTED YET";
424 1 : return ERROR_NONE;
425 : }
426 :
427 4 : OpenCDMError opencdm_session_close(struct OpenCDMSession *session)
428 : {
429 4 : kLog << debug << __func__;
430 4 : OpenCDMError result = ERROR_INVALID_SESSION;
431 4 : if (session)
432 : {
433 3 : if (session->closeSession())
434 : {
435 2 : result = ERROR_NONE;
436 : }
437 : else
438 : {
439 1 : kLog << error << "Failed to close the key session";
440 1 : result = ERROR_FAIL;
441 : }
442 : }
443 :
444 4 : return result;
445 : }
446 :
447 2 : OpenCDMBool opencdm_system_supports_server_certificate(struct OpenCDMSystem *system)
448 : {
449 2 : kLog << debug << __func__;
450 2 : if (MediaKeysCapabilitiesBackend::instance().isServerCertificateSupported(system->keySystem()))
451 : {
452 1 : return OpenCDMBool::OPENCDM_BOOL_TRUE;
453 : }
454 1 : return OpenCDMBool::OPENCDM_BOOL_FALSE;
455 : }
456 :
457 1 : OpenCDMError opencdm_session_decrypt(struct OpenCDMSession *session, uint8_t encrypted[],
458 : const uint32_t encryptedLength, const EncryptionScheme encScheme,
459 : const EncryptionPattern pattern, const uint8_t *IV, uint16_t IVLength,
460 : const uint8_t *keyId, const uint16_t keyIdLength, uint32_t initWithLast15)
461 : {
462 1 : kLog << warn << __func__ << " not implemented";
463 1 : return ERROR_FAIL;
464 : }
465 :
466 6 : OpenCDMError opencdm_get_metric_system_data(struct OpenCDMSystem *system, uint32_t *bufferLength, uint8_t *buffer)
467 : {
468 6 : kLog << debug << __func__;
469 6 : if (!system)
470 : {
471 1 : kLog << error << "System ptr is null";
472 1 : return ERROR_FAIL;
473 : }
474 :
475 5 : if (!bufferLength)
476 : {
477 1 : kLog << error << "Buffer length ptr is null";
478 1 : return ERROR_FAIL;
479 : }
480 :
481 4 : if (!buffer)
482 : {
483 1 : kLog << error << "Buffer ptr is null";
484 1 : return ERROR_FAIL;
485 : }
486 :
487 3 : std::vector<uint8_t> bufferVec;
488 3 : if (!system->getMetricSystemData(bufferVec))
489 : {
490 1 : kLog << error << "Failed to get metric system data";
491 1 : return ERROR_FAIL;
492 : }
493 :
494 2 : if (*bufferLength < bufferVec.size())
495 : {
496 2 : kLog << error << "Buffer is too small - return size " << bufferVec.size() << " does not fit in buffer of size "
497 1 : << *bufferLength;
498 1 : return ERROR_BUFFER_TOO_SMALL;
499 : }
500 :
501 1 : std::memcpy(buffer, bufferVec.data(), bufferVec.size());
502 1 : *bufferLength = bufferVec.size();
503 1 : return ERROR_NONE;
504 3 : }
|