1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 //! Example program demonstrating signed CWT processing.
18 use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError};
19
20 #[derive(Copy, Clone)]
21 struct FakeSigner {}
22
23 // Use a fake signer/verifier (to avoid pulling in lots of dependencies).
24 impl FakeSigner {
sign(&self, data: &[u8]) -> Vec<u8>25 fn sign(&self, data: &[u8]) -> Vec<u8> {
26 data.to_vec()
27 }
28
verify(&self, sig: &[u8], data: &[u8]) -> Result<(), String>29 fn verify(&self, sig: &[u8], data: &[u8]) -> Result<(), String> {
30 if sig != self.sign(data) {
31 Err("failed to verify".to_owned())
32 } else {
33 Ok(())
34 }
35 }
36 }
37
main() -> Result<(), CoseError>38 fn main() -> Result<(), CoseError> {
39 // Build a fake signer/verifier (to avoid pulling in lots of dependencies).
40 let signer = FakeSigner {};
41 let verifier = signer;
42
43 // Build a CWT ClaimsSet (cf. RFC 8392 A.3).
44 let claims = cwt::ClaimsSetBuilder::new()
45 .issuer("coap://as.example.com".to_string())
46 .subject("erikw".to_string())
47 .audience("coap://light.example.com".to_string())
48 .expiration_time(cwt::Timestamp::WholeSeconds(1444064944))
49 .not_before(cwt::Timestamp::WholeSeconds(1443944944))
50 .issued_at(cwt::Timestamp::WholeSeconds(1443944944))
51 .cwt_id(vec![0x0b, 0x71])
52 // Add additional standard claim.
53 .claim(
54 iana::CwtClaimName::Scope,
55 Value::Text("email phone".to_string()),
56 )
57 // Add additional private-use claim.
58 .private_claim(-70_000, Value::Integer(42.into()))
59 .build();
60 let aad = b"";
61
62 // Build a `CoseSign1` object.
63 let protected = coset::HeaderBuilder::new()
64 .algorithm(iana::Algorithm::ES256)
65 .build();
66 let unprotected = coset::HeaderBuilder::new()
67 .key_id(b"AsymmetricECDSA256".to_vec())
68 .build();
69 let sign1 = coset::CoseSign1Builder::new()
70 .protected(protected)
71 .unprotected(unprotected)
72 .payload(claims.clone().to_vec()?)
73 .create_signature(aad, |pt| signer.sign(pt))
74 .build();
75
76 // Serialize to bytes.
77 let sign1_data = sign1.to_vec()?;
78
79 // At the receiving end, deserialize the bytes back to a `CoseSign1` object.
80 let sign1 = coset::CoseSign1::from_slice(&sign1_data)?;
81
82 // Real code would:
83 // - Use the key ID to identify the relevant local key.
84 // - Check that the key is of the same type as `sign1.protected.algorithm`.
85
86 // Check the signature.
87 let result = sign1.verify_signature(aad, |sig, data| verifier.verify(sig, data));
88 println!("Signature verified: {:?}.", result);
89 assert!(result.is_ok());
90
91 // Now it's safe to parse the payload.
92 let recovered_claims = cwt::ClaimsSet::from_slice(&sign1.payload.unwrap())?;
93
94 assert_eq!(recovered_claims, claims);
95 Ok(())
96 }
97