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