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/cert.h"
15 #include "edhoc/bstr_encode_decode.h"
16 #include "edhoc/retrieve_cred.h"
17 
18 #include "common/crypto_wrapper.h"
19 #include "common/oscore_edhoc_error.h"
20 #include "common/print_util.h"
21 #include "common/memcpy_s.h"
22 
23 #include "cbor/edhoc_decode_id_cred_x.h"
24 
25 /**
26  * @brief 			Verifies a certificate and copies it to the cred
27  * 				buffer. It also extracts the public key
28  * 				contained in the certificate.
29  *
30  * @param static_dh_auth 	Type of the key contained in the certificate --
31  * 				signature key or static DH key.
32  * @param cred_array 		array containing credentials.
33  * @param label 		CBOR map label of id_cred_x.
34  * @param[in] cert 		The certificate.
35  * @param[in] cred 		Cred buffer.
36  * @param[in] pk 		Public key.
37  * @param[in] g 		Static DH public key.
38  * @return 			Ok or error code
39  */
40 static inline enum err
verify_cert2cred(bool static_dh_auth,struct cred_array * cred_array,enum id_cred_x_label label,struct const_byte_array * cert,struct byte_array * cred,struct byte_array * pk,struct byte_array * g)41 verify_cert2cred(bool static_dh_auth, struct cred_array *cred_array,
42 		 enum id_cred_x_label label, struct const_byte_array *cert,
43 		 struct byte_array *cred, struct byte_array *pk,
44 		 struct byte_array *g)
45 {
46 	PRINT_ARRAY("ID_CRED_x contains a certificate", cert->ptr, cert->len);
47 	TRY(encode_bstr((struct byte_array *)cert, cred));
48 
49 	bool verified = false;
50 	switch (label) {
51 	/* for now we transfer a single certificate, therefore bag and chain are the same */
52 	case x5bag:
53 	case x5chain:
54 		if (static_dh_auth) {
55 			pk->len = 0;
56 			TRY(cert_x509_verify(cert, cred_array, g, &verified));
57 		} else {
58 			g->len = 0;
59 			TRY(cert_x509_verify(cert, cred_array, pk, &verified));
60 		}
61 		break;
62 	case c5b:
63 	case c5c:
64 		if (static_dh_auth) {
65 			pk->len = 0;
66 			TRY(cert_c509_verify(cert, cred_array, g, &verified));
67 		} else {
68 			g->len = 0;
69 			TRY(cert_c509_verify(cert, cred_array, pk, &verified));
70 		}
71 		break;
72 		break;
73 
74 	default:
75 		break;
76 	}
77 
78 	if (verified) {
79 		PRINT_MSG("Certificate verification successful!\n");
80 		return ok;
81 	} else {
82 		return certificate_authentication_failed;
83 	}
84 	return ok;
85 }
86 
87 /**
88  * @brief 			Get the local cred object.
89  *
90  * @param static_dh_auth 	True if static DH is used for authentication.
91  * @param[in] cred_array 	An array of trust anchors
92  * @param[in] ID_cred 		The ID of the actual credential.
93  * @param[out] cred 		The retrievd credentials
94  * @param[out] pk 		The retrievd signature authentication public key
95  * @param[out] g 		The retrievd static DH authentication public key
96  * @return 			Ok or error code
97  */
get_local_cred(bool static_dh_auth,struct cred_array * cred_array,struct byte_array * ID_cred,struct byte_array * cred,struct byte_array * pk,struct byte_array * g)98 static enum err get_local_cred(bool static_dh_auth,
99 			       struct cred_array *cred_array,
100 			       struct byte_array *ID_cred,
101 			       struct byte_array *cred, struct byte_array *pk,
102 			       struct byte_array *g)
103 {
104 	for (uint32_t i = 0; i < cred_array->len; i++) {
105 		if ((cred_array->ptr[i].id_cred.len == ID_cred->len) &&
106 		    (0 == memcmp(cred_array->ptr[i].id_cred.ptr, ID_cred->ptr,
107 				 ID_cred->len))) {
108 			/*retrieve CRED_x*/
109 			TRY(_memcpy_s(cred->ptr, cred->len,
110 				      cred_array->ptr[i].cred.ptr,
111 				      cred_array->ptr[i].cred.len));
112 			cred->len = cred_array->ptr[i].cred.len;
113 
114 			/*retrieve PK*/
115 			if (static_dh_auth) {
116 				pk->len = 0;
117 				if (cred_array->ptr[i].g.len == 65) {
118 					/*decompressed P256 DH pk*/
119 					g->ptr[0] = 0x2;
120 					TRY(_memcpy_s(
121 						&g->ptr[1], g->len - 1,
122 						&cred_array->ptr[i].g.ptr[1],
123 						32));
124 					g->len = 33;
125 
126 				} else {
127 					TRY(_memcpy_s(g->ptr, g->len,
128 						      cred_array->ptr[i].g.ptr,
129 						      cred_array->ptr[i].g.len));
130 					g->len = cred_array->ptr[i].g.len;
131 				}
132 
133 			} else {
134 				g->len = 0;
135 				TRY(_memcpy_s(pk->ptr, pk->len,
136 					      cred_array->ptr[i].pk.ptr,
137 					      cred_array->ptr[i].pk.len));
138 				pk->len = cred_array->ptr[i].pk.len;
139 			}
140 			return ok;
141 		}
142 	}
143 
144 	return credential_not_found;
145 }
146 
retrieve_cred(bool static_dh_auth,struct cred_array * cred_array,struct byte_array * id_cred,struct byte_array * cred,struct byte_array * pk,struct byte_array * g)147 enum err retrieve_cred(bool static_dh_auth, struct cred_array *cred_array,
148 		       struct byte_array *id_cred, struct byte_array *cred,
149 		       struct byte_array *pk, struct byte_array *g)
150 {
151 	size_t decode_len = 0;
152 	struct id_cred_x_map map = { 0 };
153 
154 	TRY_EXPECT(cbor_decode_id_cred_x_map(id_cred->ptr, id_cred->len, &map,
155 					     &decode_len),
156 		   0);
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 || map.id_cred_x_map_x5u_present ||
160 	    map.id_cred_x_map_x5t_present || map.id_cred_x_map_c5u_present ||
161 	    map.id_cred_x_map_c5t_present) {
162 		TRY(get_local_cred(static_dh_auth, cred_array, id_cred, cred,
163 				   pk, g));
164 		return ok;
165 	}
166 	/*x5chain*/
167 	else if (map.id_cred_x_map_x5chain_present) {
168 		struct const_byte_array cert = BYTE_ARRAY_INIT(
169 			map.id_cred_x_map_x5chain.id_cred_x_map_x5chain.value,
170 			(uint32_t)map.id_cred_x_map_x5chain
171 				.id_cred_x_map_x5chain.len);
172 
173 		TRY(verify_cert2cred(static_dh_auth, cred_array, x5chain, &cert,
174 				     cred, pk, g));
175 		return ok;
176 	}
177 	/*x5bag*/
178 	else if (map.id_cred_x_map_x5bag_present) {
179 		struct const_byte_array cert = BYTE_ARRAY_INIT(
180 			map.id_cred_x_map_x5bag.id_cred_x_map_x5bag.value,
181 			(uint32_t)map.id_cred_x_map_x5bag.id_cred_x_map_x5bag
182 				.len);
183 		TRY(verify_cert2cred(static_dh_auth, cred_array, x5bag, &cert,
184 				     cred, pk, g));
185 		return ok;
186 	}
187 	/*c5c*/
188 	else if (map.id_cred_x_map_c5c_present) {
189 		struct const_byte_array cert = BYTE_ARRAY_INIT(
190 			map.id_cred_x_map_c5c.id_cred_x_map_c5c.value,
191 			(uint32_t)map.id_cred_x_map_c5c.id_cred_x_map_c5c.len);
192 		TRY(verify_cert2cred(static_dh_auth, cred_array, c5c, &cert,
193 				     cred, pk, g));
194 		return ok;
195 	}
196 	/*c5b*/
197 	else if (map.id_cred_x_map_c5b_present) {
198 		struct const_byte_array cert = BYTE_ARRAY_INIT(
199 			map.id_cred_x_map_c5b.id_cred_x_map_c5b.value,
200 			(uint32_t)map.id_cred_x_map_c5b.id_cred_x_map_c5b.len);
201 		TRY(verify_cert2cred(static_dh_auth, cred_array, c5b, &cert,
202 				     cred, pk, g));
203 		return ok;
204 	}
205 
206 	return credential_not_found;
207 }
208