playready/
certificate.rs

1//! Helper structs for accessing BCert and BCertChain binary formats.
2
3use crate::{
4    binary_format::{
5        bcert::{
6            Attribute, BCertChainHeader, DrmBCertDeviceInfo, DrmBCertFeatureInfo,
7            DrmBCertKeyInfoInner, PreprocessWrite,
8        },
9        StructTag, ValueAndRaw,
10    },
11    crypto::{
12        ecc_p256::{FromBytes, ToUntaggedBytes, SIGNATURE_SIZE},
13        sha256,
14    },
15};
16use binrw::{BinRead, BinWrite};
17use p256::ecdsa::{SigningKey, VerifyingKey};
18use std::io::Cursor;
19
20use crate::{
21    binary_format::bcert::{
22        AttributeInner, BCert, BCertChain, DrmBCertBasicInfo, DrmBCertKeyInfo,
23        DrmBCertManufacturerInfo, DrmBCertSignatureInfo,
24    },
25    crypto::ecc_p256,
26};
27
28const ROOT_ISSUER_KEY: [u8; 64] = [
29    0x86, 0x4d, 0x61, 0xcf, 0xf2, 0x25, 0x6e, 0x42, 0x2c, 0x56, 0x8b, 0x3c, 0x28, 0x00, 0x1c, 0xfb,
30    0x3e, 0x15, 0x27, 0x65, 0x85, 0x84, 0xba, 0x05, 0x21, 0xb7, 0x9b, 0x18, 0x28, 0xd9, 0x36, 0xde,
31    0x1d, 0x82, 0x6a, 0x8f, 0xc3, 0xe6, 0xe7, 0xfa, 0x7a, 0x90, 0xd5, 0xca, 0x29, 0x46, 0xf1, 0xf6,
32    0x4a, 0x2e, 0xfb, 0x9f, 0x5d, 0xcf, 0xfe, 0x7e, 0x43, 0x4e, 0xb4, 0x42, 0x93, 0xfa, 0xc5, 0xab,
33];
34
35#[derive(Debug, Clone)]
36struct Certificate {
37    parsed: BCert,
38    raw: Vec<u8>,
39}
40
41impl Certificate {
42    fn new(bcert: BCert, raw: Vec<u8>) -> Self {
43        Self { parsed: bcert, raw }
44    }
45
46    fn into_bcert_and_raw(self) -> (BCert, Vec<u8>) {
47        (self.parsed, self.raw)
48    }
49
50    fn from_bytes(bytes: &[u8]) -> Result<Self, binrw::Error> {
51        Self::from_vec(bytes.to_vec())
52    }
53
54    fn from_vec(vec: Vec<u8>) -> Result<Self, binrw::Error> {
55        let parsed = BCert::read(&mut Cursor::new(&vec))?;
56
57        Ok(Self { parsed, raw: vec })
58    }
59
60    fn find_attribute(&self, tag: u16) -> Option<&Attribute> {
61        self.parsed.attributes.iter().find(|a| a.tag == tag)
62    }
63
64    fn find_key_by_usage(&self, usage: u32) -> Option<&[u8]> {
65        let attribute = self.find_attribute(DrmBCertKeyInfo::TAG)?;
66
67        let cert_info = match &attribute.inner {
68            AttributeInner::DrmBCertKeyInfo(inner) => Some(inner),
69            _ => None,
70        }?;
71
72        cert_info
73            .cert_keys
74            .iter()
75            .find(|c| c.usages.contains(&usage))
76            .map(|c| c.key.as_slice())
77    }
78
79    fn public_signing_key(&self) -> Option<&[u8]> {
80        self.find_key_by_usage(1)
81    }
82
83    fn public_encryption_key(&self) -> Option<&[u8]> {
84        self.find_key_by_usage(2)
85    }
86
87    fn issuer_key(&self) -> Option<&[u8]> {
88        self.find_key_by_usage(6)
89    }
90
91    fn public_group_key(&self) -> Option<&[u8]> {
92        let attribute = self.find_attribute(DrmBCertSignatureInfo::TAG)?;
93
94        match &attribute.inner {
95            AttributeInner::DrmBCertSignatureInfo(inner) => Some(&inner.signature_key),
96            _ => None,
97        }
98    }
99
100    fn verify_signature(&self, public_key: &[u8]) -> Result<(), crate::Error> {
101        let attribute = self.find_attribute(DrmBCertSignatureInfo::TAG).ok_or(
102            crate::Error::BinaryObjectNotFoundError("DrmBCertSignatureInfo"),
103        )?;
104
105        let sig_info = match &attribute.inner {
106            AttributeInner::DrmBCertSignatureInfo(inner) => Some(inner),
107            _ => None,
108        }
109        .ok_or(crate::Error::BinaryObjectNotFoundError(
110            "DrmBCertSignatureInfo",
111        ))?;
112
113        if public_key != sig_info.signature_key {
114            return Err(crate::Error::PublicKeyMismatchError("BCert"));
115        }
116
117        let msg_end = self.raw.len() - usize::try_from(attribute.length)?;
118
119        ecc_p256::verify(
120            &VerifyingKey::from_bytes(&sig_info.signature_key)?,
121            self.raw
122                .get(..msg_end)
123                .ok_or(crate::Error::SliceOutOfBoundsError(
124                    "cert.raw",
125                    self.raw.len(),
126                ))?,
127            &sig_info.signature,
128        )
129        .map_err(|e| e.into())
130    }
131
132    fn new_leaf(
133        cert_id: [u8; 16],
134        client_id: [u8; 16],
135        security_level: u32,
136        manufacturer_info: Attribute,
137        public_signing_key: Vec<u8>,
138        public_encryption_key: Vec<u8>,
139        group_key: &SigningKey,
140    ) -> Result<Self, crate::Error> {
141        let public_group_key = group_key
142            .verifying_key()
143            .as_affine()
144            .to_untagged_bytes()
145            .to_vec();
146
147        let attributes = vec![
148            Attribute {
149                flags: 1,
150                inner: AttributeInner::DrmBCertBasicInfo(DrmBCertBasicInfo {
151                    cert_id,
152                    security_level,
153                    cert_type: 2,
154                    public_key_digest: sha256::hash(&public_signing_key).try_into().unwrap(),
155                    expiration_date: u32::MAX,
156                    client_id,
157                    ..Default::default()
158                }),
159                ..Default::default()
160            },
161            Attribute {
162                flags: 1,
163                inner: AttributeInner::DrmBCertDeviceInfo(DrmBCertDeviceInfo {
164                    max_license: 10240,
165                    max_header: 15360,
166                    max_chain_depth: 2,
167                }),
168                ..Default::default()
169            },
170            Attribute {
171                flags: 1,
172                inner: AttributeInner::DrmBCertFeatureInfo(DrmBCertFeatureInfo {
173                    features: vec![4, 9, 13],
174                    ..Default::default()
175                }),
176                ..Default::default()
177            },
178            Attribute {
179                flags: 1,
180                inner: AttributeInner::DrmBCertKeyInfo(DrmBCertKeyInfo {
181                    cert_keys: vec![
182                        DrmBCertKeyInfoInner {
183                            type_: 1,
184                            key: public_signing_key,
185                            usages: vec![1],
186                            ..Default::default()
187                        },
188                        DrmBCertKeyInfoInner {
189                            type_: 1,
190                            key: public_encryption_key,
191                            usages: vec![2],
192                            ..Default::default()
193                        },
194                    ],
195                    ..Default::default()
196                }),
197                ..Default::default()
198            },
199            manufacturer_info,
200            Attribute {
201                flags: 1,
202                inner: AttributeInner::DrmBCertSignatureInfo(DrmBCertSignatureInfo {
203                    signature_type: 1,
204                    signature: vec![0u8; SIGNATURE_SIZE],
205                    signature_key: public_group_key,
206                    ..Default::default()
207                }),
208                ..Default::default()
209            },
210        ];
211
212        let mut cert = BCert {
213            version: 1,
214            attributes,
215            ..Default::default()
216        };
217
218        let mut raw = Vec::<u8>::new();
219        cert.preprocess_write();
220        cert.write(&mut Cursor::new(&mut raw))?;
221
222        let signature = ecc_p256::sign(
223            group_key,
224            raw.get(0..usize::try_from(cert.certificate_length)?)
225                .ok_or(crate::Error::SliceOutOfBoundsError("cert.raw", raw.len()))?,
226        );
227
228        assert!(signature.len() == SIGNATURE_SIZE);
229
230        if let AttributeInner::DrmBCertSignatureInfo(inner) =
231            &mut cert.attributes.last_mut().unwrap().inner
232        {
233            inner.signature.copy_from_slice(&signature)
234        }
235
236        raw.clear();
237        cert.write(&mut Cursor::new(&mut raw))?;
238
239        Ok(Self { parsed: cert, raw })
240    }
241}
242
243impl TryFrom<&[u8]> for Certificate {
244    type Error = binrw::Error;
245
246    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
247        Self::from_bytes(value)
248    }
249}
250
251impl TryFrom<Vec<u8>> for Certificate {
252    type Error = binrw::Error;
253
254    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
255        Self::from_vec(value)
256    }
257}
258
259impl From<ValueAndRaw<BCert>> for Certificate {
260    fn from(value: ValueAndRaw<BCert>) -> Self {
261        let (val, raw) = value.into_value_and_raw();
262        Self::new(val, raw)
263    }
264}
265
266impl From<Certificate> for ValueAndRaw<BCert> {
267    fn from(value: Certificate) -> Self {
268        Self::from(value.into_bcert_and_raw())
269    }
270}
271
272/// Wrapper structure for `BCertChain` format.
273#[derive(Debug, Clone)]
274pub struct CertificateChain {
275    header: BCertChainHeader,
276    certificates: Vec<Certificate>,
277    raw: Vec<u8>,
278}
279
280impl CertificateChain {
281    /// Creates new [`CertificateChain`] from bytes.
282    pub fn from_bytes(bytes: &[u8]) -> Result<Self, binrw::Error> {
283        Self::from_vec(bytes.to_vec())
284    }
285
286    /// Creates new [`CertificateChain`] from vector.
287    pub fn from_vec(vec: Vec<u8>) -> Result<Self, binrw::Error> {
288        let parsed = BCertChain::read(&mut Cursor::new(&vec))?;
289
290        let header = parsed.header;
291        let certificates = parsed
292            .certificates
293            .into_iter()
294            .map(Certificate::from)
295            .collect();
296
297        Ok(Self {
298            header,
299            certificates,
300            raw: vec,
301        })
302    }
303
304    /// Creates raw bytes of [`CertificateChain`].
305    pub fn raw(&self) -> &[u8] {
306        &self.raw
307    }
308
309    /// Returns security level (SL????) of the device.
310    pub fn security_level(&self) -> Result<u32, crate::Error> {
311        let first_cert = self
312            .certificates
313            .first()
314            .ok_or(crate::Error::CertificateMissingError)?;
315
316        let attribute = first_cert
317            .find_attribute(DrmBCertBasicInfo::TAG)
318            .ok_or(crate::Error::BinaryObjectNotFoundError("DrmBCertBasicInfo"))?;
319
320        match &attribute.inner {
321            AttributeInner::DrmBCertBasicInfo(inner) => Ok(inner.security_level),
322            _ => Err(crate::Error::BinaryObjectNotFoundError("DrmBCertBasicInfo")),
323        }
324    }
325
326    /// Returns public part of device's signing key.
327    pub fn public_signing_key(&self) -> Result<&[u8], crate::Error> {
328        self.certificates
329            .first()
330            .ok_or(crate::Error::CertificateMissingError)?
331            .public_signing_key()
332            .ok_or(crate::Error::BinaryObjectNotFoundError(
333                "DrmBCertKeyInfo.signing_key",
334            ))
335    }
336
337    /// Returns public part of device's encryption key.
338    pub fn public_encryption_key(&self) -> Result<&[u8], crate::Error> {
339        self.certificates
340            .first()
341            .ok_or(crate::Error::CertificateMissingError)?
342            .public_encryption_key()
343            .ok_or(crate::Error::BinaryObjectNotFoundError(
344                "DrmBCertKeyInfo.encryption_key",
345            ))
346    }
347
348    /// Returns public part of device's group key.
349    pub fn public_group_key(&self) -> Result<&[u8], crate::Error> {
350        self.certificates
351            .first()
352            .ok_or(crate::Error::CertificateMissingError)?
353            .public_group_key()
354            .ok_or(crate::Error::BinaryObjectNotFoundError(
355                "DrmBCertSignatureInfo.public_group_key",
356            ))
357    }
358
359    /// Returns name of the device.
360    pub fn name(&self) -> Result<String, crate::Error> {
361        fn from_null_terminated_string(s: Vec<u8>) -> String {
362            let s = s.into_iter().take_while(|c| *c != b'\x00').collect();
363            String::from_utf8(s)
364                .inspect_err(|e| log::error!("Failed to create utf8 string: {e:?}"))
365                .unwrap_or_default()
366        }
367
368        let first_cert = self
369            .certificates
370            .first()
371            .ok_or(crate::Error::CertificateMissingError)?;
372
373        let attribute = first_cert
374            .find_attribute(DrmBCertManufacturerInfo::TAG)
375            .ok_or(crate::Error::BinaryObjectNotFoundError(
376                "DrmBCertManufacturerInfo",
377            ))?;
378
379        match &attribute.inner {
380            AttributeInner::DrmBCertManufacturerInfo(inner) => {
381                let manufacturer = from_null_terminated_string(inner.manufacturer_name.clone());
382                let model_name = from_null_terminated_string(inner.model_name.clone());
383                let model_number = from_null_terminated_string(inner.model_number.clone());
384
385                Ok(format!("{manufacturer} {model_name} {model_number}"))
386            }
387            _ => Err(crate::Error::BinaryObjectNotFoundError(
388                "DrmBCertManufacturerInfo",
389            )),
390        }
391    }
392
393    /// Performs signature verification of all certificates.
394    pub fn verify_signatures(&self) -> Result<(), crate::Error> {
395        if self.certificates.is_empty() {
396            return Err(crate::Error::CertificateMissingError);
397        }
398
399        let mut issuer_key = ROOT_ISSUER_KEY;
400
401        for i in (0..self.certificates.len()).rev() {
402            let cert = &self.certificates[i];
403            cert.verify_signature(&issuer_key)?;
404
405            match cert.issuer_key() {
406                Some(key) => issuer_key.copy_from_slice(key),
407                None => {
408                    if i != 0 {
409                        return Err(crate::Error::CertificateVerificationError(i));
410                    }
411                }
412            }
413        }
414
415        Ok(())
416    }
417
418    /// Provisions certificate chain by creating new leaf certificate.
419    pub fn provision(
420        mut self,
421        cert_id: [u8; 16],
422        client_id: [u8; 16],
423        public_signing_key: Vec<u8>,
424        public_encryption_key: Vec<u8>,
425        group_key: &SigningKey,
426    ) -> Result<Self, crate::Error> {
427        let public_group_key = group_key.verifying_key().as_affine().to_untagged_bytes();
428
429        self.certificates = self
430            .certificates
431            .into_iter()
432            .skip_while(|c| {
433                c.issuer_key()
434                    .map(|c| *c != *public_group_key)
435                    .unwrap_or(true)
436            })
437            .collect();
438
439        if self.certificates.is_empty() {
440            return Err(crate::Error::PublicKeyMismatchError("group key"));
441        }
442
443        let first_cert = self
444            .certificates
445            .first()
446            .ok_or(crate::Error::CertificateMissingError)?;
447
448        let manufacturer_info = first_cert
449            .find_attribute(DrmBCertManufacturerInfo::TAG)
450            .ok_or(crate::Error::BinaryObjectNotFoundError(
451                "DrmBCertManufacturerInfo",
452            ))
453            .cloned()?;
454
455        let security_level = self.security_level()?;
456
457        let new_leaf = Certificate::new_leaf(
458            cert_id,
459            client_id,
460            security_level,
461            manufacturer_info,
462            public_signing_key,
463            public_encryption_key,
464            group_key,
465        )?;
466
467        self.certificates.insert(0, new_leaf);
468
469        let mut bcertchain = BCertChain {
470            header: self.header,
471            certificates: self
472                .certificates
473                .into_iter()
474                .map(ValueAndRaw::<BCert>::from)
475                .collect(),
476        };
477
478        bcertchain
479            .certificates
480            .iter_mut()
481            .for_each(|c| c.use_raw = true);
482
483        self.raw.clear();
484        let mut raw = self.raw;
485        bcertchain.preprocess_write();
486        bcertchain.write(&mut Cursor::new(&mut raw))?;
487
488        let header = bcertchain.header;
489        let certificates = bcertchain
490            .certificates
491            .into_iter()
492            .map(Certificate::from)
493            .collect();
494
495        Ok(Self {
496            header,
497            certificates,
498            raw,
499        })
500    }
501}
502
503impl TryFrom<&[u8]> for CertificateChain {
504    type Error = binrw::Error;
505
506    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
507        Self::from_bytes(value)
508    }
509}
510
511impl TryFrom<Vec<u8>> for CertificateChain {
512    type Error = binrw::Error;
513
514    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
515        Self::from_vec(value)
516    }
517}