playready/
device.rs

1//! Creating and parsing devices.
2
3use crate::{
4    binary_format::{self, device::PRD_SCALAR_SIZE},
5    certificate::CertificateChain,
6    crypto::ecc_p256::{FromBytes, Keypair, ToUntaggedBytes, SCALAR_SIZE},
7};
8use binrw::{BinRead, BinWrite};
9use p256::ecdsa::SigningKey;
10use p256::elliptic_curve::PrimeField;
11use rand::{thread_rng, Rng};
12use std::{
13    fs::File,
14    io::{Cursor, Read},
15    path::Path,
16};
17
18/// Represents PlayReady device. Usually created from .prd file.
19#[derive(Debug, Clone)]
20pub struct Device {
21    group_key: Option<SigningKey>,
22    encryption_key: Keypair,
23    signing_key: SigningKey,
24    cert_chain: CertificateChain,
25}
26
27impl Device {
28    /// Creates new [`Device`].
29    pub fn new(
30        group_key: Option<SigningKey>,
31        encryption_key: Keypair,
32        signing_key: SigningKey,
33        cert_chain: CertificateChain,
34    ) -> Self {
35        Self {
36            group_key,
37            encryption_key,
38            signing_key,
39            cert_chain,
40        }
41    }
42
43    /// Creates new [`Device`] from bytes.
44    pub fn from_bytes(bytes: &[u8]) -> Result<Self, crate::Error> {
45        let device = binary_format::device::Device::read(&mut Cursor::new(bytes))?;
46
47        let group_key = match &device.inner {
48            binary_format::device::DeviceInner::V2(_) => None,
49            binary_format::device::DeviceInner::V3(v3) => Some(&v3.group_key),
50        };
51
52        let group_key = match group_key {
53            Some(group_key) => Some(SigningKey::from_slice(&group_key[..SCALAR_SIZE])?),
54            None => None,
55        };
56
57        let encryption_key = match &device.inner {
58            binary_format::device::DeviceInner::V2(v2) => &v2.encryption_key,
59            binary_format::device::DeviceInner::V3(v3) => &v3.encryption_key,
60        };
61
62        let signing_key = match &device.inner {
63            binary_format::device::DeviceInner::V2(v2) => &v2.signing_key,
64            binary_format::device::DeviceInner::V3(v3) => &v3.signing_key,
65        };
66
67        let encryption_key = Keypair::from_bytes(&encryption_key[..SCALAR_SIZE])?;
68        let signing_key = SigningKey::from_slice(&signing_key[..SCALAR_SIZE])?;
69
70        let group_certificate = match device.inner {
71            binary_format::device::DeviceInner::V2(v2) => v2.group_certificate,
72            binary_format::device::DeviceInner::V3(v3) => v3.group_certificate,
73        };
74
75        let cert_chain = CertificateChain::from_vec(group_certificate)?;
76
77        Ok(Self {
78            group_key,
79            encryption_key,
80            signing_key,
81            cert_chain,
82        })
83    }
84
85    /// Creates new [`Device`] from .prd file.
86    ///
87    /// # Arguments
88    ///
89    /// `path` - path to .prd file
90    pub fn from_prd(path: impl AsRef<Path>) -> Result<Self, crate::Error> {
91        let mut file = File::open(path)?;
92        let mut bytes = Vec::<u8>::new();
93        file.read_to_end(&mut bytes)?;
94
95        Self::from_bytes(&bytes)
96    }
97
98    /// Returns device signing key.
99    pub fn signing_key(&self) -> &SigningKey {
100        &self.signing_key
101    }
102
103    /// Returns device encryption key.
104    pub fn encryption_key(&self) -> &Keypair {
105        &self.encryption_key
106    }
107
108    /// Returns device group certificate.
109    pub fn group_certificate(&self) -> &[u8] {
110        self.cert_chain.raw()
111    }
112
113    /// Returns device group key.
114    pub fn group_key(&self) -> Option<&SigningKey> {
115        self.group_key.as_ref()
116    }
117
118    /// Returns name of the device parsed from certificate chain.
119    pub fn name(&self) -> Result<String, crate::Error> {
120        self.cert_chain.name()
121    }
122
123    /// Returns security level (SL????) of the device parsed from certificate chain.
124    pub fn security_level(&self) -> Result<u32, crate::Error> {
125        self.cert_chain.security_level()
126    }
127
128    /// Performs signature verification of certificates bundled in [`CertificateChain`].
129    pub fn verify(&self) -> Result<(), crate::Error> {
130        let public_signing_key = self
131            .signing_key
132            .verifying_key()
133            .as_affine()
134            .to_untagged_bytes();
135
136        let public_encryption_key = self
137            .encryption_key
138            .public()
139            .as_element()
140            .to_untagged_bytes();
141
142        if *public_signing_key != *self.cert_chain.public_signing_key()? {
143            return Err(crate::Error::PublicKeyMismatchError("signing key"));
144        }
145
146        if *public_encryption_key != *self.cert_chain.public_encryption_key()? {
147            return Err(crate::Error::PublicKeyMismatchError("encryption key"));
148        }
149
150        if let Some(group_key) = self.group_key() {
151            let group_key = group_key.verifying_key().as_affine().to_untagged_bytes();
152
153            if *group_key != *self.cert_chain.public_group_key()? {
154                return Err(crate::Error::PublicKeyMismatchError("group key"));
155            }
156        }
157
158        self.cert_chain.verify_signatures()
159    }
160
161    /// Creates and provisions device from certificate chain and group key.
162    pub fn provision(
163        cert_chain: CertificateChain,
164        group_key: SigningKey,
165    ) -> Result<Self, crate::Error> {
166        let mut rng = thread_rng();
167
168        let client_id = rng.gen::<[u8; 16]>();
169        let cert_id = rng.gen::<[u8; 16]>();
170
171        let encryption_key = Keypair::generate(&mut rng);
172        let signing_key = SigningKey::random(&mut rng);
173
174        let public_encryption_key = encryption_key
175            .public()
176            .as_element()
177            .to_untagged_bytes()
178            .to_vec();
179
180        let public_signing_key = signing_key
181            .verifying_key()
182            .as_affine()
183            .to_untagged_bytes()
184            .to_vec();
185
186        let cert_chain = cert_chain.provision(
187            cert_id,
188            client_id,
189            public_signing_key,
190            public_encryption_key,
191            &group_key,
192        )?;
193
194        cert_chain.verify_signatures()?;
195
196        Ok(Self {
197            group_key: Some(group_key),
198            encryption_key,
199            signing_key,
200            cert_chain,
201        })
202    }
203
204    /// Generates reprovisioned [`Device`].
205    pub fn reprovision(self) -> Result<Self, crate::Error> {
206        let Device {
207            cert_chain,
208            group_key,
209            ..
210        } = self;
211
212        let group_key = group_key.ok_or(crate::Error::GroupKeyMissingError)?;
213
214        Self::provision(cert_chain, group_key)
215    }
216
217    /// Creates and provisions device from file containing certificate chain
218    /// (usually named bgroupcert.dat) and file with group key (usually zgpriv.dat).
219    pub fn provision_from_files(
220        group_cert_path: impl AsRef<Path>,
221        group_key_path: impl AsRef<Path>,
222    ) -> Result<Self, crate::Error> {
223        let mut file = File::open(group_cert_path)?;
224        let mut bytes = Vec::<u8>::new();
225        file.read_to_end(&mut bytes)?;
226
227        let cert_chain = CertificateChain::from_bytes(&bytes)?;
228
229        file = File::open(group_key_path)?;
230        bytes.clear();
231        file.read_to_end(&mut bytes)?;
232
233        let group_key = SigningKey::from_slice(bytes.get(..SCALAR_SIZE).ok_or(
234            crate::Error::SliceOutOfBoundsError("group_key", bytes.len()),
235        )?)?;
236
237        Self::provision(cert_chain, group_key)
238    }
239
240    /// Serializes and writes device to file specified by path.
241    pub fn write_to_file(&self, path: impl AsRef<Path>) -> Result<(), crate::Error> {
242        let mut group_key = [0u8; PRD_SCALAR_SIZE];
243        let mut encryption_key = [0u8; PRD_SCALAR_SIZE];
244        let mut signing_key = [0u8; PRD_SCALAR_SIZE];
245
246        group_key[..SCALAR_SIZE].copy_from_slice(
247            &self
248                .group_key
249                .as_ref()
250                .ok_or(crate::Error::GroupKeyMissingError)?
251                .to_bytes(),
252        );
253
254        encryption_key[..SCALAR_SIZE]
255            .copy_from_slice(&self.encryption_key.secret().expose_scalar().to_repr());
256        signing_key[..SCALAR_SIZE].copy_from_slice(&self.signing_key.to_bytes());
257
258        let group_certificate = self.group_certificate().to_vec();
259        let group_certificate_length = u32::try_from(group_certificate.len()).unwrap();
260
261        let device = binary_format::device::Device {
262            version: 3,
263            inner: binary_format::device::DeviceInner::V3(binary_format::device::DeviceV3 {
264                group_key,
265                encryption_key,
266                signing_key,
267                group_certificate_length,
268                group_certificate,
269            }),
270        };
271
272        let mut file = File::create(path)?;
273        device.write(&mut file)?;
274
275        Ok(())
276    }
277}
278
279impl TryFrom<&[u8]> for Device {
280    type Error = crate::Error;
281
282    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
283        Self::from_bytes(value)
284    }
285}