playready/
certificate.rs

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