1 /*
2 * Copyright (c) 2019 Siddharth Chandrasekaran <siddharth@embedjournal.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <logging/log.h>
8 LOG_MODULE_DECLARE(osdp, CONFIG_OSDP_LOG_LEVEL);
9
10 #include <string.h>
11 #include "osdp_common.h"
12
13 #define TAG "SC: "
14
15 #define OSDP_SC_EOM_MARKER 0x80 /* End of Message Marker */
16
17 /* Default key as specified in OSDP specification */
18 static const uint8_t osdp_scbk_default[16] = {
19 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
20 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
21 };
22
osdp_compute_scbk(struct osdp_pd * pd,uint8_t * scbk)23 void osdp_compute_scbk(struct osdp_pd *pd, uint8_t *scbk)
24 {
25 int i;
26 struct osdp *ctx = TO_CTX(pd);
27
28 memcpy(scbk, pd->sc.pd_client_uid, 8);
29 for (i = 8; i < 16; i++) {
30 scbk[i] = ~scbk[i - 8];
31 }
32 osdp_encrypt(ctx->sc_master_key, NULL, scbk, 16);
33 }
34
osdp_compute_session_keys(struct osdp * ctx)35 void osdp_compute_session_keys(struct osdp *ctx)
36 {
37 int i;
38 struct osdp_pd *pd = GET_CURRENT_PD(ctx);
39
40 if (ISSET_FLAG(pd, PD_FLAG_SC_USE_SCBKD)) {
41 memcpy(pd->sc.scbk, osdp_scbk_default, 16);
42 } else {
43 /**
44 * Compute SCBK only in CP mode. PD mode, expect to already have
45 * the SCBK (sent from application layer).
46 */
47 if (ISSET_FLAG(pd, PD_FLAG_PD_MODE) == 0) {
48 osdp_compute_scbk(pd, pd->sc.scbk);
49 }
50 }
51
52 memset(pd->sc.s_enc, 0, 16);
53 memset(pd->sc.s_mac1, 0, 16);
54 memset(pd->sc.s_mac2, 0, 16);
55
56 pd->sc.s_enc[0] = 0x01; pd->sc.s_enc[1] = 0x82;
57 pd->sc.s_mac1[0] = 0x01; pd->sc.s_mac1[1] = 0x01;
58 pd->sc.s_mac2[0] = 0x01; pd->sc.s_mac2[1] = 0x02;
59
60 for (i = 2; i < 8; i++) {
61 pd->sc.s_enc[i] = pd->sc.cp_random[i - 2];
62 pd->sc.s_mac1[i] = pd->sc.cp_random[i - 2];
63 pd->sc.s_mac2[i] = pd->sc.cp_random[i - 2];
64 }
65
66 osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_enc, 16);
67 osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_mac1, 16);
68 osdp_encrypt(pd->sc.scbk, NULL, pd->sc.s_mac2, 16);
69 }
70
osdp_compute_cp_cryptogram(struct osdp_pd * pd)71 void osdp_compute_cp_cryptogram(struct osdp_pd *pd)
72 {
73 /* cp_cryptogram = AES-ECB( pd_random[8] || cp_random[8], s_enc ) */
74 memcpy(pd->sc.cp_cryptogram + 0, pd->sc.pd_random, 8);
75 memcpy(pd->sc.cp_cryptogram + 8, pd->sc.cp_random, 8);
76 osdp_encrypt(pd->sc.s_enc, NULL, pd->sc.cp_cryptogram, 16);
77 }
78
79 /**
80 * Like memcmp; but operates at constant time.
81 *
82 * Returns 0 if memory pointed to by s1 and and s2 are identical; non-zero
83 * otherwise.
84 */
osdp_ct_compare(const void * s1,const void * s2,size_t len)85 static int osdp_ct_compare(const void *s1, const void *s2, size_t len)
86 {
87 size_t i, ret = 0;
88 const uint8_t *_s1 = s1;
89 const uint8_t *_s2 = s2;
90
91 for (i = 0; i < len; i++) {
92 ret |= _s1[i] ^ _s2[i];
93 }
94 return (int)ret;
95 }
96
osdp_verify_cp_cryptogram(struct osdp_pd * pd)97 int osdp_verify_cp_cryptogram(struct osdp_pd *pd)
98 {
99 uint8_t cp_crypto[16];
100
101 /* cp_cryptogram = AES-ECB( pd_random[8] || cp_random[8], s_enc ) */
102 memcpy(cp_crypto + 0, pd->sc.pd_random, 8);
103 memcpy(cp_crypto + 8, pd->sc.cp_random, 8);
104 osdp_encrypt(pd->sc.s_enc, NULL, cp_crypto, 16);
105
106 if (osdp_ct_compare(pd->sc.cp_cryptogram, cp_crypto, 16) != 0) {
107 return -1;
108 }
109 return 0;
110 }
111
osdp_compute_pd_cryptogram(struct osdp_pd * pd)112 void osdp_compute_pd_cryptogram(struct osdp_pd *pd)
113 {
114 /* pd_cryptogram = AES-ECB( cp_random[8] || pd_random[8], s_enc ) */
115 memcpy(pd->sc.pd_cryptogram + 0, pd->sc.cp_random, 8);
116 memcpy(pd->sc.pd_cryptogram + 8, pd->sc.pd_random, 8);
117 osdp_encrypt(pd->sc.s_enc, NULL, pd->sc.pd_cryptogram, 16);
118 }
119
osdp_verify_pd_cryptogram(struct osdp_pd * pd)120 int osdp_verify_pd_cryptogram(struct osdp_pd *pd)
121 {
122 uint8_t pd_crypto[16];
123
124 /* pd_cryptogram = AES-ECB( cp_random[8] || pd_random[8], s_enc ) */
125 memcpy(pd_crypto + 0, pd->sc.cp_random, 8);
126 memcpy(pd_crypto + 8, pd->sc.pd_random, 8);
127 osdp_encrypt(pd->sc.s_enc, NULL, pd_crypto, 16);
128
129 if (osdp_ct_compare(pd->sc.pd_cryptogram, pd_crypto, 16) != 0) {
130 return -1;
131 }
132 return 0;
133 }
134
osdp_compute_rmac_i(struct osdp_pd * pd)135 void osdp_compute_rmac_i(struct osdp_pd *pd)
136 {
137 /* rmac_i = AES-ECB( AES-ECB( cp_cryptogram, s_mac1 ), s_mac2 ) */
138 memcpy(pd->sc.r_mac, pd->sc.cp_cryptogram, 16);
139 osdp_encrypt(pd->sc.s_mac1, NULL, pd->sc.r_mac, 16);
140 osdp_encrypt(pd->sc.s_mac2, NULL, pd->sc.r_mac, 16);
141 }
142
osdp_decrypt_data(struct osdp_pd * pd,int is_cmd,uint8_t * data,int length)143 int osdp_decrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length)
144 {
145 int i;
146 uint8_t iv[16];
147
148 if (length % 16 != 0) {
149 LOG_ERR(TAG "decrypt_pkt invalid len:%d", length);
150 return -1;
151 }
152
153 memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16);
154 for (i = 0; i < 16; i++) {
155 iv[i] = ~iv[i];
156 }
157
158 osdp_decrypt(pd->sc.s_enc, iv, data, length);
159
160 while (data[length - 1] == 0x00) {
161 length--;
162 }
163 if (data[length - 1] != OSDP_SC_EOM_MARKER) {
164 return -1;
165 }
166 data[length - 1] = 0;
167
168 return length - 1;
169 }
170
osdp_encrypt_data(struct osdp_pd * pd,int is_cmd,uint8_t * data,int length)171 int osdp_encrypt_data(struct osdp_pd *pd, int is_cmd, uint8_t *data, int length)
172 {
173 int i, pad_len;
174 uint8_t iv[16];
175
176 data[length] = OSDP_SC_EOM_MARKER; /* append EOM marker */
177 pad_len = AES_PAD_LEN(length + 1);
178 if ((pad_len - length - 1) > 0) {
179 memset(data + length + 1, 0, pad_len - length - 1);
180 }
181 memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16);
182 for (i = 0; i < 16; i++) {
183 iv[i] = ~iv[i];
184 }
185
186 osdp_encrypt(pd->sc.s_enc, iv, data, pad_len);
187
188 return pad_len;
189 }
190
osdp_compute_mac(struct osdp_pd * pd,int is_cmd,const uint8_t * data,int len)191 int osdp_compute_mac(struct osdp_pd *pd, int is_cmd,
192 const uint8_t *data, int len)
193 {
194 int pad_len;
195 uint8_t buf[CONFIG_OSDP_UART_BUFFER_LENGTH] = { 0 };
196 uint8_t iv[16];
197
198 memcpy(buf, data, len);
199 pad_len = (len % 16 == 0) ? len : AES_PAD_LEN(len);
200 if (len % 16 != 0) {
201 buf[len] = 0x80; /* end marker */
202 }
203 /**
204 * MAC for data blocks B[1] .. B[N] (post padding) is computed as:
205 * IV1 = R_MAC (or) C_MAC -- depending on is_cmd
206 * IV2 = B[N-1] after -- AES-CBC ( IV1, B[1] to B[N-1], SMAC-1 )
207 * MAC = AES-ECB ( IV2, B[N], SMAC-2 )
208 */
209
210 memcpy(iv, is_cmd ? pd->sc.r_mac : pd->sc.c_mac, 16);
211 if (pad_len > 16) {
212 /* N-1 blocks -- encrypted with SMAC-1 */
213 osdp_encrypt(pd->sc.s_mac1, iv, buf, pad_len - 16);
214 /* N-1 th block is the IV for N th block */
215 memcpy(iv, buf + pad_len - 32, 16);
216 }
217
218 /* N-th Block encrypted with SMAC-2 == MAC */
219 osdp_encrypt(pd->sc.s_mac2, iv, buf + pad_len - 16, 16);
220 memcpy(is_cmd ? pd->sc.c_mac : pd->sc.r_mac, buf + pad_len - 16, 16);
221
222 return 0;
223 }
224
osdp_sc_init(struct osdp_pd * pd)225 void osdp_sc_init(struct osdp_pd *pd)
226 {
227 uint8_t key[16];
228
229 if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) {
230 memcpy(key, pd->sc.scbk, 16);
231 }
232 memset(&pd->sc, 0, sizeof(struct osdp_secure_channel));
233 if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) {
234 memcpy(pd->sc.scbk, key, 16);
235 }
236 if (ISSET_FLAG(pd, PD_FLAG_PD_MODE)) {
237 pd->sc.pd_client_uid[0] = BYTE_0(pd->id.vendor_code);
238 pd->sc.pd_client_uid[1] = BYTE_1(pd->id.vendor_code);
239 pd->sc.pd_client_uid[2] = BYTE_0(pd->id.model);
240 pd->sc.pd_client_uid[3] = BYTE_1(pd->id.version);
241 pd->sc.pd_client_uid[4] = BYTE_0(pd->id.serial_number);
242 pd->sc.pd_client_uid[5] = BYTE_1(pd->id.serial_number);
243 pd->sc.pd_client_uid[6] = BYTE_2(pd->id.serial_number);
244 pd->sc.pd_client_uid[7] = BYTE_3(pd->id.serial_number);
245 }
246 }
247