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 <string.h>
13 
14 #include "edhoc.h"
15 
16 #include "edhoc/cert.h"
17 #include "edhoc/signature_or_mac_msg.h"
18 #include "edhoc/retrieve_cred.h"
19 
20 #include "common/crypto_wrapper.h"
21 #include "common/oscore_edhoc_error.h"
22 #include "common/print_util.h"
23 #include "common/memcpy_s.h"
24 
25 #include "cbor/edhoc_decode_id_cred_x.h"
26 
27 /**
28  * @brief 	This function verifies a certificate and copies it to the cred
29  * 		buffer. It also extracts the public key contained in the
30  * 		certificate.
31  *
32  * @param static_dh_auth type of the key contained in the certificate --
33  * 			signature key or static DH key.
34  * @param cred_array array containing credentials
35  * @param cred_num number of credentials
36  * @param label map label of id_cred_x
37  * @param cert the certificate
38  * @param cert_len length of the certificate
39  * @param cred cred buffer
40  * @param cred_len length of cred
41  * @param pk public key buffer
42  * @param pk_len length of pk
43  * @param g static DH public key buffer
44  * @param g_len length of g
45  * @return enum err
46  */
47 static inline enum err
verify_cert2cred(bool static_dh_auth,struct other_party_cred * cred_array,uint16_t cred_num,enum id_cred_x_label label,const uint8_t * cert,uint32_t cert_len,uint8_t * cred,uint32_t * cred_len,uint8_t * pk,uint32_t * pk_len,uint8_t * g,uint32_t * g_len)48 verify_cert2cred(bool static_dh_auth, struct other_party_cred *cred_array,
49 		 uint16_t cred_num, enum id_cred_x_label label,
50 		 const uint8_t *cert, uint32_t cert_len, uint8_t *cred,
51 		 uint32_t *cred_len, uint8_t *pk, uint32_t *pk_len, uint8_t *g,
52 		 uint32_t *g_len)
53 {
54 	PRINT_ARRAY("ID_CRED_x contains a certificate", cert, cert_len);
55 	TRY(encode_byte_string(cert, cert_len, cred, cred_len));
56 
57 	bool verified = false;
58 	switch (label) {
59 	/* for now we transfer a single certificate, therefore bag and chain are the same */
60 	case x5bag:
61 	case x5chain:
62 		if (static_dh_auth) {
63 			*pk_len = 0;
64 			TRY(cert_x509_verify(cert, cert_len, cred_array,
65 					     cred_num, g, g_len, &verified));
66 		} else {
67 			*g_len = 0;
68 			TRY(cert_x509_verify(cert, cert_len, cred_array,
69 					     cred_num, pk, pk_len, &verified));
70 		}
71 		break;
72 	case c5b:
73 	case c5c:
74 		if (static_dh_auth) {
75 			*pk_len = 0;
76 			TRY(cert_c509_verify(cert, cert_len, cred_array,
77 					     cred_num, g, g_len, &verified));
78 		} else {
79 			*g_len = 0;
80 			TRY(cert_c509_verify(cert, cert_len, cred_array,
81 					     cred_num, pk, pk_len, &verified));
82 		}
83 		break;
84 		break;
85 
86 	default:
87 		break;
88 	}
89 
90 	if (verified) {
91 		PRINT_MSG("Certificate verification successful!\n");
92 		return ok;
93 	} else {
94 		return certificate_authentication_failed;
95 	}
96 }
97 
get_local_cred(bool static_dh_auth,struct other_party_cred * cred_array,uint16_t cred_num,uint8_t * id_cred,uint32_t id_cred_len,uint8_t * cred,uint32_t * cred_len,uint8_t * pk,uint32_t * pk_len,uint8_t * g,uint32_t * g_len)98 static enum err get_local_cred(bool static_dh_auth,
99 			       struct other_party_cred *cred_array,
100 			       uint16_t cred_num, uint8_t *id_cred,
101 			       uint32_t id_cred_len, uint8_t *cred,
102 			       uint32_t *cred_len, uint8_t *pk,
103 			       uint32_t *pk_len, uint8_t *g, uint32_t *g_len)
104 {
105 	for (uint16_t i = 0; i < cred_num; i++) {
106 		if ((cred_array[i].id_cred.len == id_cred_len) &&
107 		    (0 ==
108 		     memcmp(cred_array[i].id_cred.ptr, id_cred, id_cred_len))) {
109 			/*retrieve CRED_x*/
110 			TRY(_memcpy_s(cred, *cred_len, cred_array[i].cred.ptr,
111 				      cred_array[i].cred.len));
112 			*cred_len = cred_array[i].cred.len;
113 
114 			/*retrieve PK*/
115 			if (static_dh_auth) {
116 				*pk_len = 0;
117 				if (cred_array[i].g.len == 65) {
118 					/*decompressed P256 DH pk*/
119 					g[0] = 0x2;
120 					TRY(_memcpy_s(&g[1], *g_len - 1,
121 						      &cred_array[i].g.ptr[1],
122 						      32));
123 					*g_len = 33;
124 
125 				} else {
126 					TRY(_memcpy_s(g, *g_len,
127 						      cred_array[i].g.ptr,
128 						      cred_array[i].g.len));
129 					*g_len = cred_array[i].g.len;
130 				}
131 
132 			} else {
133 				*g_len = 0;
134 				TRY(_memcpy_s(pk, *pk_len, cred_array[i].pk.ptr,
135 					      cred_array[i].pk.len));
136 				*pk_len = cred_array[i].pk.len;
137 			}
138 			return ok;
139 		}
140 	}
141 
142 	return credential_not_found;
143 }
144 
retrieve_cred(bool static_dh_auth,struct other_party_cred * cred_array,uint16_t cred_num,uint8_t * id_cred,uint32_t id_cred_len,uint8_t * cred,uint32_t * cred_len,uint8_t * pk,uint32_t * pk_len,uint8_t * g,uint32_t * g_len)145 enum err retrieve_cred(bool static_dh_auth, struct other_party_cred *cred_array,
146 		       uint16_t cred_num, uint8_t *id_cred,
147 		       uint32_t id_cred_len, uint8_t *cred, uint32_t *cred_len,
148 		       uint8_t *pk, uint32_t *pk_len, uint8_t *g,
149 		       uint32_t *g_len)
150 {
151 	size_t decode_len = 0;
152 	struct id_cred_x_map map;
153 
154 	TRY_EXPECT(cbor_decode_id_cred_x_map(id_cred, id_cred_len, &map,
155 					     &decode_len),
156 		   true);
157 	/*the cred should be locally available on the device if
158 	kid, x5u, x5t, c5u, c5t is used*/
159 	if ((map._id_cred_x_map_kid_present != 0) ||
160 	    (map._id_cred_x_map_x5u_present != 0) ||
161 	    (map._id_cred_x_map_x5t_present != 0) ||
162 	    (map._id_cred_x_map_c5u_present != 0) ||
163 	    (map._id_cred_x_map_c5t_present != 0)) {
164 		TRY(get_local_cred(static_dh_auth, cred_array, cred_num,
165 				   id_cred, id_cred_len, cred, cred_len, pk,
166 				   pk_len, g, g_len));
167 		return ok;
168 	}
169 	/*x5chain*/
170 	else if (map._id_cred_x_map_x5chain_present != 0) {
171 		TRY(verify_cert2cred(
172 			static_dh_auth, cred_array, cred_num, x5chain,
173 			map._id_cred_x_map_x5chain._id_cred_x_map_x5chain.value,
174 			(uint32_t) map._id_cred_x_map_x5chain._id_cred_x_map_x5chain.len,
175 			cred, cred_len, pk, pk_len, g, g_len));
176 		return ok;
177 	}
178 	/*x5bag*/
179 	else if (map._id_cred_x_map_x5bag_present != 0) {
180 		TRY(verify_cert2cred(
181 			static_dh_auth, cred_array, cred_num, x5bag,
182 			map._id_cred_x_map_x5bag._id_cred_x_map_x5bag.value,
183 			(uint32_t) map._id_cred_x_map_x5bag._id_cred_x_map_x5bag.len, cred,
184 			cred_len, pk, pk_len, g, g_len));
185 		return ok;
186 	}
187 	/*c5c*/
188 	else if (map._id_cred_x_map_c5c_present != 0) {
189 		TRY(verify_cert2cred(
190 			static_dh_auth, cred_array, cred_num, c5c,
191 			map._id_cred_x_map_c5c._id_cred_x_map_c5c.value,
192 			(uint32_t) map._id_cred_x_map_c5c._id_cred_x_map_c5c.len, cred,
193 			cred_len, pk, pk_len, g, g_len));
194 		return ok;
195 	}
196 	/*c5b*/
197 	else if (map._id_cred_x_map_c5b_present != 0) {
198 		TRY(verify_cert2cred(
199 			static_dh_auth, cred_array, cred_num, c5b,
200 			map._id_cred_x_map_c5b._id_cred_x_map_c5b.value,
201 			(uint32_t) map._id_cred_x_map_c5b._id_cred_x_map_c5b.len, cred,
202 			cred_len, pk, pk_len, g, g_len));
203 		return ok;
204 	}
205 
206 	return credential_not_found;
207 }
208