Skip to main content

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