1 /*
2    Copyright (c) 2021 Fraunhofer AISEC. See the COPYRIGHT
3    file at the top-level directory of this distribution.
4 
5    Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6    http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7    <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8    option. This file may not be copied, modified, or distributed
9    except according to those terms.
10 */
11 
12 #include <stdint.h>
13 #include <stdbool.h>
14 
15 #include "edhoc/retrieve_cred.h"
16 #include "edhoc/plaintext.h"
17 #include "edhoc/signature_or_mac_msg.h"
18 #include "edhoc/int_encode_decode.h"
19 
20 #include "common/oscore_edhoc_error.h"
21 #include "common/memcpy_s.h"
22 #include "common/print_util.h"
23 
24 #include "cbor/edhoc_decode_plaintext2.h"
25 #include "cbor/edhoc_decode_plaintext3.h"
26 #include "cbor/edhoc_encode_id_cred_x.h"
27 
28 /**
29  * @brief 			Encodes ID_CRED_x as a CBOR map.
30  * @param label 		The CBOR map label.
31  * @param algo 			The EDHOC hash algorithm used in x5t. This
32  * 				parameter can take any other value when xchain
33  * 				or kid are used.
34  * @param id 			The actual credential identifier.
35  * @param id_len 		Length of id.
36  * @param[out] id_cred_x	The encoded value.
37  * @retval			Ok or error.
38  */
id_cred_x_encode(enum id_cred_x_label label,int algo,const void * id,uint32_t id_len,struct byte_array * id_cred_x)39 static enum err id_cred_x_encode(enum id_cred_x_label label, int algo,
40 				 const void *id, uint32_t id_len,
41 				 struct byte_array *id_cred_x)
42 {
43 	struct id_cred_x_map map = { 0 };
44 	size_t payload_len_out;
45 
46 	switch (label) {
47 	case kid:
48 		//todo update that to v15
49 		map.id_cred_x_map_kid_present = true;
50 		map.id_cred_x_map_kid.id_cred_x_map_kid_choice =
51 			id_cred_x_map_kid_int_c;
52 		map.id_cred_x_map_kid.id_cred_x_map_kid_int =
53 			*((const int32_t *)id);
54 		break;
55 	case x5chain:
56 		map.id_cred_x_map_x5chain_present = true;
57 		map.id_cred_x_map_x5chain.id_cred_x_map_x5chain.value = id;
58 		map.id_cred_x_map_x5chain.id_cred_x_map_x5chain.len = id_len;
59 		break;
60 	case x5t:
61 		map.id_cred_x_map_x5t_present = true;
62 		map.id_cred_x_map_x5t.id_cred_x_map_x5t_alg_choice =
63 			id_cred_x_map_x5t_alg_int_c;
64 		map.id_cred_x_map_x5t.id_cred_x_map_x5t_alg_int = algo;
65 		map.id_cred_x_map_x5t.id_cred_x_map_x5t_hash.value = id;
66 		map.id_cred_x_map_x5t.id_cred_x_map_x5t_hash.len = id_len;
67 		break;
68 	default:
69 		break;
70 	}
71 
72 	TRY_EXPECT(cbor_encode_id_cred_x_map(id_cred_x->ptr, id_cred_x->len,
73 					     &map, &payload_len_out),
74 		   0);
75 
76 	id_cred_x->len = (uint32_t)payload_len_out;
77 
78 	return ok;
79 }
80 
plaintext2_split(struct byte_array * ptxt,struct byte_array * c_r,struct byte_array * id_cred_r,struct byte_array * sign_or_mac,struct byte_array * ead)81 static enum err plaintext2_split(struct byte_array *ptxt,
82 				 struct byte_array *c_r,
83 				 struct byte_array *id_cred_r,
84 				 struct byte_array *sign_or_mac,
85 				 struct byte_array *ead)
86 {
87 	size_t decode_len = 0;
88 	struct ptxt2 p;
89 
90 	TRY_EXPECT(cbor_decode_ptxt2(ptxt->ptr, ptxt->len, &p, &decode_len), 0);
91 
92 	/*decode C_R*/
93 	if (p.ptxt2_C_R_choice == ptxt2_C_R_bstr_c) {
94 		TRY(_memcpy_s(c_r->ptr, c_r->len, p.ptxt2_C_R_bstr.value,
95 			      (uint32_t)p.ptxt2_C_R_bstr.len));
96 		c_r->len = (uint32_t)p.ptxt2_C_R_bstr.len;
97 	} else {
98 		/*provide C_R in encoded form if it was an int*/
99 		/*this is how it C_R was chosen by the responder*/
100 		TRY(encode_int(&p.ptxt2_C_R_int, 1, c_r));
101 	}
102 
103 	/*ID_CRED_R*/
104 	if (p.ptxt2_ID_CRED_R_choice == ptxt2_ID_CRED_R_map2_m_c) {
105 		if (p.ptxt2_ID_CRED_R_map2_m.map2_x5chain_present) {
106 			PRINT_MSG("ID_CRED_R is x5chain\n");
107 			TRY(id_cred_x_encode(
108 				x5chain, 0,
109 				p.ptxt2_ID_CRED_R_map2_m.map2_x5chain
110 					.map2_x5chain.value,
111 				(uint32_t)p.ptxt2_ID_CRED_R_map2_m.map2_x5chain
112 					.map2_x5chain.len,
113 				id_cred_r));
114 		}
115 		if (p.ptxt2_ID_CRED_R_map2_m.map2_x5t_present) {
116 			PRINT_MSG("ID_CRED_R is x5t\n");
117 			TRY(id_cred_x_encode(x5t,
118 					     p.ptxt2_ID_CRED_R_map2_m.map2_x5t
119 						     .map2_x5t_alg_int,
120 					     p.ptxt2_ID_CRED_R_map2_m.map2_x5t
121 						     .map2_x5t_hash.value,
122 					     (uint32_t)p.ptxt2_ID_CRED_R_map2_m
123 						     .map2_x5t.map2_x5t_hash.len,
124 					     id_cred_r));
125 		}
126 	} else {
127 		/*Note that if ID_CRED_x contains a single 'kid' parameter,
128             i.e., ID_CRED_R = { 4 : kid_x }, only the byte string kid_x
129             is conveyed in the plaintext encoded as a bstr or int*/
130 		if (p.ptxt2_ID_CRED_R_choice == ptxt2_ID_CRED_R_map2_m_c) {
131 			TRY(id_cred_x_encode(
132 				kid, 0, p.ptxt2_ID_CRED_R_bstr.value,
133 				(uint32_t)p.ptxt2_ID_CRED_R_bstr.len,
134 				id_cred_r));
135 
136 		} else {
137 			int _kid = p.ptxt2_ID_CRED_R_int;
138 			TRY(id_cred_x_encode(kid, 0, &_kid, 1, id_cred_r));
139 		}
140 	}
141 	TRY(_memcpy_s(sign_or_mac->ptr, sign_or_mac->len,
142 		      p.ptxt2_SGN_or_MAC_2.value,
143 		      (uint32_t)p.ptxt2_SGN_or_MAC_2.len));
144 	sign_or_mac->len = (uint32_t)p.ptxt2_SGN_or_MAC_2.len;
145 
146 	if (p.ptxt2_EAD_2_present == true) {
147 		TRY(_memcpy_s(ead->ptr, ead->len, p.ptxt2_EAD_2.value,
148 			      (uint32_t)p.ptxt2_EAD_2.len));
149 		ead->len = (uint32_t)p.ptxt2_EAD_2.len;
150 	} else {
151 		if (ead->len) {
152 			ead->len = 0;
153 		}
154 	}
155 
156 	return ok;
157 }
158 
plaintext3_split(struct byte_array * ptxt,struct byte_array * id_cred_i,struct byte_array * sign_or_mac,struct byte_array * ead)159 static enum err plaintext3_split(struct byte_array *ptxt,
160 				 struct byte_array *id_cred_i,
161 				 struct byte_array *sign_or_mac,
162 				 struct byte_array *ead)
163 {
164 	size_t decode_len = 0;
165 	struct ptxt3 p;
166 
167 	TRY_EXPECT(cbor_decode_ptxt3(ptxt->ptr, ptxt->len, &p, &decode_len), 0);
168 
169 	/*ID_CRED_I*/
170 	if (p.ptxt3_ID_CRED_I_choice == ptxt3_ID_CRED_I_map3_m_c) {
171 		if (p.ptxt3_ID_CRED_I_map3_m.map3_x5chain_present) {
172 			PRINT_MSG("ID_CRED_I is x5chain\n");
173 			TRY(id_cred_x_encode(
174 				x5chain, 0,
175 				p.ptxt3_ID_CRED_I_map3_m.map3_x5chain
176 					.map3_x5chain.value,
177 				(uint32_t)p.ptxt3_ID_CRED_I_map3_m.map3_x5chain
178 					.map3_x5chain.len,
179 				id_cred_i));
180 		}
181 		if (p.ptxt3_ID_CRED_I_map3_m.map3_x5t_present) {
182 			PRINT_MSG("ID_CRED_I is x5t\n");
183 			TRY(id_cred_x_encode(x5t,
184 					     p.ptxt3_ID_CRED_I_map3_m.map3_x5t
185 						     .map3_x5t_alg_int,
186 					     p.ptxt3_ID_CRED_I_map3_m.map3_x5t
187 						     .map3_x5t_hash.value,
188 					     (uint32_t)p.ptxt3_ID_CRED_I_map3_m
189 						     .map3_x5t.map3_x5t_hash.len,
190 					     id_cred_i));
191 		}
192 	} else {
193 		/*Note that if ID_CRED_x contains a single 'kid' parameter,
194             i.e., ID_CRED_I = { 4 : kid_x }, only the byte string kid_x
195             is conveyed in the plaintext encoded as a bstr or int*/
196 		if (p.ptxt3_ID_CRED_I_choice == ptxt3_ID_CRED_I_map3_m_c) {
197 			TRY(id_cred_x_encode(
198 				kid, 0, p.ptxt3_ID_CRED_I_bstr.value,
199 				(uint32_t)p.ptxt3_ID_CRED_I_bstr.len,
200 				id_cred_i));
201 
202 		} else {
203 			int _kid = p.ptxt3_ID_CRED_I_int;
204 			TRY(id_cred_x_encode(kid, 0, &_kid, 1, id_cred_i));
205 		}
206 	}
207 	TRY(_memcpy_s(sign_or_mac->ptr, sign_or_mac->len,
208 		      p.ptxt3_SGN_or_MAC_3.value,
209 		      (uint32_t)p.ptxt3_SGN_or_MAC_3.len));
210 	sign_or_mac->len = (uint32_t)p.ptxt3_SGN_or_MAC_3.len;
211 
212 	if (p.ptxt3_EAD_3_present == true) {
213 		TRY(_memcpy_s(ead->ptr, ead->len, p.ptxt3_EAD_3.value,
214 			      (uint32_t)p.ptxt3_EAD_3.len));
215 		ead->len = (uint32_t)p.ptxt3_EAD_3.len;
216 	} else {
217 		if (ead->len) {
218 			ead->len = 0;
219 		}
220 	}
221 	return ok;
222 }
223 
plaintext_split(struct byte_array * ptxt,struct byte_array * c_r,struct byte_array * id_cred_x,struct byte_array * sign_or_mac,struct byte_array * ead)224 enum err plaintext_split(struct byte_array *ptxt, struct byte_array *c_r,
225 			 struct byte_array *id_cred_x,
226 			 struct byte_array *sign_or_mac, struct byte_array *ead)
227 {
228 	/*C_R is present only in plaintext 2*/
229 	if (c_r != NULL) {
230 		return plaintext2_split(ptxt, c_r, id_cred_x, sign_or_mac, ead);
231 	} else {
232 		return plaintext3_split(ptxt, id_cred_x, sign_or_mac, ead);
233 	}
234 }
235