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,
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}
39
40impl Certificate {
41    fn new(bcert: BCert) -> Self {
42        Self { parsed: bcert }
43    }
44
45    fn from_bytes(bytes: &[u8]) -> Result<Self, binrw::Error> {
46        Self::from_vec(bytes.to_vec())
47    }
48
49    fn from_vec(vec: Vec<u8>) -> Result<Self, binrw::Error> {
50        let parsed = BCert::read(&mut Cursor::new(&vec))?;
51
52        Ok(Self { parsed })
53    }
54
55    fn find_attribute(&self, tag: u16) -> Option<&Attribute> {
56        self.parsed.attributes.iter().find(|a| a.tag == tag)
57    }
58
59    fn find_key_by_usage(&self, usage: u32) -> Option<&[u8]> {
60        let attribute = self.find_attribute(DrmBCertKeyInfo::TAG)?;
61
62        let cert_info = match &attribute.inner {
63            AttributeInner::DrmBCertKeyInfo(inner) => Some(inner),
64            _ => 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(1)
76    }
77
78    fn public_encryption_key(&self) -> Option<&[u8]> {
79        self.find_key_by_usage(2)
80    }
81
82    fn issuer_key(&self) -> Option<&[u8]> {
83        self.find_key_by_usage(6)
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
100        let sig_info = match &attribute.inner {
101            AttributeInner::DrmBCertSignatureInfo(inner) => Some(inner),
102            _ => None,
103        }
104        .ok_or(crate::Error::BinaryObjectNotFoundError(
105            "DrmBCertSignatureInfo",
106        ))?;
107
108        if public_key != sig_info.signature_key {
109            return Err(crate::Error::PublicKeyMismatchError("BCert"));
110        }
111
112        ecc_p256::verify(
113            &VerifyingKey::from_bytes(&sig_info.signature_key)?,
114            cert_bytes,
115            &sig_info.signature,
116        )
117        .map_err(|e| e.into())
118    }
119
120    fn new_leaf(
121        cert_id: [u8; 16],
122        client_id: [u8; 16],
123        security_level: u32,
124        manufacturer_info: Attribute,
125        public_signing_key: Vec<u8>,
126        public_encryption_key: Vec<u8>,
127        group_key: &SigningKey,
128    ) -> Result<Self, crate::Error> {
129        let public_group_key = group_key
130            .verifying_key()
131            .as_affine()
132            .to_untagged_bytes()
133            .to_vec();
134
135        let attributes = vec![
136            Attribute {
137                flags: 1,
138                inner: AttributeInner::DrmBCertBasicInfo(DrmBCertBasicInfo {
139                    cert_id,
140                    security_level,
141                    cert_type: 2,
142                    public_key_digest: sha256::hash(&public_signing_key).try_into().unwrap(),
143                    expiration_date: u32::MAX,
144                    client_id,
145                    ..Default::default()
146                }),
147                ..Default::default()
148            },
149            Attribute {
150                flags: 1,
151                inner: AttributeInner::DrmBCertDeviceInfo(DrmBCertDeviceInfo {
152                    max_license: 10240,
153                    max_header: 15360,
154                    max_chain_depth: 2,
155                }),
156                ..Default::default()
157            },
158            Attribute {
159                flags: 1,
160                inner: AttributeInner::DrmBCertFeatureInfo(DrmBCertFeatureInfo {
161                    features: vec![4, 9, 13],
162                    ..Default::default()
163                }),
164                ..Default::default()
165            },
166            Attribute {
167                flags: 1,
168                inner: AttributeInner::DrmBCertKeyInfo(DrmBCertKeyInfo {
169                    cert_keys: vec![
170                        DrmBCertKeyInfoInner {
171                            type_: 1,
172                            key: public_signing_key,
173                            usages: vec![1],
174                            ..Default::default()
175                        },
176                        DrmBCertKeyInfoInner {
177                            type_: 1,
178                            key: public_encryption_key,
179                            usages: vec![2],
180                            ..Default::default()
181                        },
182                    ],
183                    ..Default::default()
184                }),
185                ..Default::default()
186            },
187            manufacturer_info,
188            Attribute {
189                flags: 1,
190                inner: AttributeInner::DrmBCertSignatureInfo(DrmBCertSignatureInfo {
191                    signature_type: 1,
192                    signature: vec![0u8; SIGNATURE_SIZE],
193                    signature_key: public_group_key,
194                    ..Default::default()
195                }),
196                ..Default::default()
197            },
198        ];
199
200        let mut cert = BCert {
201            version: 1,
202            attributes,
203            ..Default::default()
204        };
205
206        let mut raw = Vec::<u8>::new();
207        cert.preprocess_write();
208        cert.write(&mut Cursor::new(&mut raw))?;
209
210        let signature = ecc_p256::sign(
211            group_key,
212            raw.get(0..usize::try_from(cert.certificate_length)?)
213                .ok_or(crate::Error::SliceOutOfBoundsError("cert.raw", raw.len()))?,
214        );
215
216        assert!(signature.len() == SIGNATURE_SIZE);
217
218        if let AttributeInner::DrmBCertSignatureInfo(inner) =
219            &mut cert.attributes.last_mut().unwrap().inner
220        {
221            inner.signature.copy_from_slice(&signature)
222        }
223
224        raw.clear();
225        cert.write(&mut Cursor::new(&mut raw))?;
226
227        Ok(Self { parsed: cert })
228    }
229}
230
231impl TryFrom<&[u8]> for Certificate {
232    type Error = binrw::Error;
233
234    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
235        Self::from_bytes(value)
236    }
237}
238
239impl TryFrom<Vec<u8>> for Certificate {
240    type Error = binrw::Error;
241
242    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
243        Self::from_vec(value)
244    }
245}
246
247impl From<BCert> for Certificate {
248    fn from(value: BCert) -> Self {
249        Self::new(value)
250    }
251}
252
253impl From<Certificate> for BCert {
254    fn from(value: Certificate) -> Self {
255        value.parsed
256    }
257}
258
259/// Wrapper structure for `BCertChain` format.
260#[derive(Clone)]
261pub struct CertificateChain {
262    header: BCertChainHeader,
263    certificates: Vec<Certificate>,
264    raw: Vec<u8>,
265}
266
267impl std::fmt::Debug for CertificateChain {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        f.debug_struct("CertificateChain")
270            .field("header", &self.header)
271            .field("certificates", &self.certificates)
272            .finish()
273    }
274}
275
276impl CertificateChain {
277    /// Creates new [`CertificateChain`] from bytes.
278    pub fn from_bytes(bytes: &[u8]) -> Result<Self, binrw::Error> {
279        Self::from_vec(bytes.to_vec())
280    }
281
282    /// Creates new [`CertificateChain`] from vector.
283    pub fn from_vec(vec: Vec<u8>) -> Result<Self, binrw::Error> {
284        let parsed = BCertChain::read(&mut Cursor::new(&vec))?;
285
286        let header = parsed.header;
287        let certificates = parsed
288            .certificates
289            .into_iter()
290            .map(Certificate::from)
291            .collect();
292
293        Ok(Self {
294            header,
295            certificates,
296            raw: vec,
297        })
298    }
299
300    /// Creates raw bytes of [`CertificateChain`].
301    pub fn raw(&self) -> &[u8] {
302        &self.raw
303    }
304
305    /// Returns security level (SL????) of the device.
306    pub fn security_level(&self) -> Result<u32, crate::Error> {
307        let first_cert = self
308            .certificates
309            .first()
310            .ok_or(crate::Error::CertificateMissingError)?;
311
312        let attribute = first_cert
313            .find_attribute(DrmBCertBasicInfo::TAG)
314            .ok_or(crate::Error::BinaryObjectNotFoundError("DrmBCertBasicInfo"))?;
315
316        match &attribute.inner {
317            AttributeInner::DrmBCertBasicInfo(inner) => Ok(inner.security_level),
318            _ => Err(crate::Error::BinaryObjectNotFoundError("DrmBCertBasicInfo")),
319        }
320    }
321
322    /// Returns public part of device's signing key.
323    pub fn public_signing_key(&self) -> Result<&[u8], crate::Error> {
324        self.certificates
325            .first()
326            .ok_or(crate::Error::CertificateMissingError)?
327            .public_signing_key()
328            .ok_or(crate::Error::BinaryObjectNotFoundError(
329                "DrmBCertKeyInfo.signing_key",
330            ))
331    }
332
333    /// Returns public part of device's encryption key.
334    pub fn public_encryption_key(&self) -> Result<&[u8], crate::Error> {
335        self.certificates
336            .first()
337            .ok_or(crate::Error::CertificateMissingError)?
338            .public_encryption_key()
339            .ok_or(crate::Error::BinaryObjectNotFoundError(
340                "DrmBCertKeyInfo.encryption_key",
341            ))
342    }
343
344    /// Returns public part of device's group key.
345    pub fn public_group_key(&self) -> Result<&[u8], crate::Error> {
346        self.certificates
347            .first()
348            .ok_or(crate::Error::CertificateMissingError)?
349            .public_group_key()
350            .ok_or(crate::Error::BinaryObjectNotFoundError(
351                "DrmBCertSignatureInfo.public_group_key",
352            ))
353    }
354
355    /// Returns name of the device.
356    pub fn name(&self) -> Result<String, crate::Error> {
357        let attribute = self
358            .certificates
359            .iter()
360            .filter_map(|c| c.find_attribute(DrmBCertManufacturerInfo::TAG))
361            .next()
362            .ok_or(crate::Error::BinaryObjectNotFoundError(
363                "DrmBCertManufacturerInfo",
364            ))?;
365
366        match &attribute.inner {
367            AttributeInner::DrmBCertManufacturerInfo(inner) => {
368                let manufacturer = inner.manufacturer_name.to_string();
369                let model_name = inner.model_name.to_string();
370                let model_number = inner.model_number.to_string();
371
372                Ok(format!("{manufacturer} {model_name} {model_number}"))
373            }
374            _ => Err(crate::Error::BinaryObjectNotFoundError(
375                "DrmBCertManufacturerInfo",
376            )),
377        }
378    }
379
380    /// Performs signature verification of all certificates.
381    pub fn verify_signatures(&self) -> Result<(), crate::Error> {
382        if self.certificates.is_empty() {
383            return Err(crate::Error::CertificateMissingError);
384        }
385
386        let mut issuer_key = ROOT_ISSUER_KEY;
387
388        for i in (0..self.certificates.len()).rev() {
389            let cert = &self.certificates[i];
390            cert.verify_signature(&issuer_key, self.cert_bytes(i)?)?;
391
392            match cert.issuer_key() {
393                Some(key) => issuer_key.copy_from_slice(key),
394                None => {
395                    if i != 0 {
396                        return Err(crate::Error::CertificateVerificationError(i));
397                    }
398                }
399            }
400        }
401
402        Ok(())
403    }
404
405    /// Provisions certificate chain by creating new leaf certificate.
406    pub fn provision(
407        mut self,
408        cert_id: [u8; 16],
409        client_id: [u8; 16],
410        public_signing_key: Vec<u8>,
411        public_encryption_key: Vec<u8>,
412        group_key: &SigningKey,
413    ) -> Result<Self, crate::Error> {
414        let public_group_key = group_key.verifying_key().as_affine().to_untagged_bytes();
415
416        self.certificates = self
417            .certificates
418            .into_iter()
419            .skip_while(|c| {
420                c.issuer_key()
421                    .map(|c| *c != *public_group_key)
422                    .unwrap_or(true)
423            })
424            .collect();
425
426        if self.certificates.is_empty() {
427            return Err(crate::Error::PublicKeyMismatchError("group key"));
428        }
429
430        let first_cert = self
431            .certificates
432            .first()
433            .ok_or(crate::Error::CertificateMissingError)?;
434
435        let manufacturer_info = first_cert
436            .find_attribute(DrmBCertManufacturerInfo::TAG)
437            .ok_or(crate::Error::BinaryObjectNotFoundError(
438                "DrmBCertManufacturerInfo",
439            ))
440            .cloned()?;
441
442        let security_level = self.security_level()?;
443
444        let new_leaf = Certificate::new_leaf(
445            cert_id,
446            client_id,
447            security_level,
448            manufacturer_info,
449            public_signing_key,
450            public_encryption_key,
451            group_key,
452        )?;
453
454        self.certificates.insert(0, new_leaf);
455
456        let mut bcertchain = BCertChain {
457            header: self.header,
458            certificates: self.certificates.into_iter().map(BCert::from).collect(),
459        };
460
461        self.raw.clear();
462        let mut raw = self.raw;
463        bcertchain.preprocess_write();
464        bcertchain.write(&mut Cursor::new(&mut raw))?;
465
466        let header = bcertchain.header;
467        let certificates = bcertchain
468            .certificates
469            .into_iter()
470            .map(Certificate::from)
471            .collect();
472
473        Ok(Self {
474            header,
475            certificates,
476            raw,
477        })
478    }
479
480    fn cert_bytes(&self, n: usize) -> Result<&[u8], crate::Error> {
481        let mut offset: usize = 20; // sizeof("CHAI") + sizeof(BCertChainHeader)
482
483        let Some(cert) = self.certificates.get(n) else {
484            return Err(crate::Error::CertificateMissingError);
485        };
486
487        for i in 0..n {
488            offset += usize::try_from(self.certificates[i].parsed.total_length)?;
489        }
490
491        let cert_end = offset + usize::try_from(cert.parsed.certificate_length)?;
492
493        self.raw
494            .get(offset..cert_end)
495            .ok_or(crate::Error::SliceOutOfBoundsError("cert.raw", cert_end))
496    }
497}
498
499impl TryFrom<&[u8]> for CertificateChain {
500    type Error = binrw::Error;
501
502    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
503        Self::from_bytes(value)
504    }
505}
506
507impl TryFrom<Vec<u8>> for CertificateChain {
508    type Error = binrw::Error;
509
510    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
511        Self::from_vec(value)
512    }
513}