1#include <stdlib.h>
2#include <string.h>
3
4#include "mc_internal.h"
5#include "mgrandom.h"
6
7/* naive der parser */
8typedef struct {
9 const u8* data;
10 size_t size;
11 size_t cursor;
12} DERReader;
13
14static u8 cipher_byte(MCCipher* cipher);
15static i8 der_length(DERReader* reader, size_t* length);
16static i8 der_value(DERReader* reader, u8 tag, DERReader* value);
17static i8 rsa_public_key(const u8* der, size_t der_size, br_rsa_public_key* key, char* error, size_t error_size);
18static void twos_complement(u8* data, size_t size);
19
20/* generate next cipher stream byte
21 returns cipher byte */
22static u8 cipher_byte(MCCipher* cipher)
23{
24 u8 zero_iv[16] = { 0 };
25 u8 block[16];
26 memcpy(block, cipher->state, 16);
27 br_aes_ct_cbcenc_run(&cipher->key, zero_iv, block, sizeof(block));
28 return block[0];
29}
30
31/* read DER length
32 returns 1 on success, 0 on failure */
33static i8 der_length(DERReader* reader, size_t* length)
34{
35 u8 first;
36 size_t value = 0;
37 u32 count;
38 u32 i;
39
40 if (reader->cursor >= reader->size)
41 return 0;
42 first = reader->data[reader->cursor++];
43 if (!(first & 0x80)) {
44 *length = first;
45 return *length <= reader->size - reader->cursor;
46 }
47 count = first & 0x7f;
48 if (count == 0 || count > sizeof(size_t) || count > reader->size - reader->cursor)
49 return 0;
50 for (i = 0; i < count; ++i)
51 value = (value << 8) | reader->data[reader->cursor++];
52 if (value > reader->size - reader->cursor)
53 return 0;
54 *length = value;
55 return 1;
56}
57
58/* read DER value by tag
59 returns 1 on success, 0 on failure */
60static i8 der_value(DERReader* reader, u8 tag, DERReader* value)
61{
62 size_t length;
63 if (reader->cursor >= reader->size || reader->data[reader->cursor++] != tag || !der_length(reader, &length))
64 return 0;
65 value->data = reader->data + reader->cursor;
66 value->size = length;
67 value->cursor = 0;
68 reader->cursor += length;
69 return 1;
70}
71
72/* parse the server's X.509 RSA pubkey for BearSSL
73 returns 1 on success, 0 on failure */
74static i8 rsa_public_key(const u8* der, size_t der_size, br_rsa_public_key* key, char* error, size_t error_size)
75{
76 DERReader root = { der, der_size, 0 };
77 DERReader spki;
78 DERReader algorithm;
79 DERReader bits;
80 DERReader rsa;
81 DERReader modulus;
82 DERReader exponent;
83
84 if (!der_value(&root, 0x30, &spki) || !der_value(&spki, 0x30, &algorithm) || !der_value(&spki, 0x03, &bits) ||
85 bits.size < 1 || bits.data[0] != 0) {
86 mc_set_error(MC_EC_INVALID_PUBLIC_KEY, error, error_size, "invalid X.509 RSA public key");
87 return 0;
88 }
89 bits.cursor = 1;
90 if (!der_value(&bits, 0x30, &rsa) || !der_value(&rsa, 0x02, &modulus) || !der_value(&rsa, 0x02, &exponent)) {
91 mc_set_error(MC_EC_INVALID_PUBLIC_KEY, error, error_size, "invalid RSA public key integers");
92 return 0;
93 }
94 while (modulus.size > 1 && modulus.data[0] == 0) {
95 ++modulus.data;
96 --modulus.size;
97 }
98 while (exponent.size > 1 && exponent.data[0] == 0) {
99 ++exponent.data;
100 --exponent.size;
101 }
102 key->n = (unsigned char*)modulus.data;
103 key->nlen = modulus.size;
104 key->e = (unsigned char*)exponent.data;
105 key->elen = exponent.size;
106 return key->nlen >= 64 && key->elen > 0;
107}
108
109/* convert bytes to twos complement in place */
110static void twos_complement(u8* data, size_t size)
111{
112 size_t i = size;
113 u32 carry = 1;
114 while (i > 0) {
115 u32 value;
116 --i;
117 value = (u32)(data[i] ^ 0xff) + carry;
118 data[i] = (u8)value;
119 carry = value >> 8;
120 }
121}
122
123void mc_cipher_init(MCCipher* cipher, const u8 key[16])
124{
125 br_aes_ct_cbcenc_init(&cipher->key, key, 16);
126 memcpy(cipher->state, key, 16);
127}
128
129void mc_cipher_encrypt(MCCipher* cipher, u8* data, size_t size)
130{
131 size_t i;
132 for (i = 0; i < size; ++i) {
133 u8 encrypted = data[i] ^ cipher_byte(cipher);
134 memmove(cipher->state, cipher->state + 1, 15);
135 cipher->state[15] = encrypted;
136 data[i] = encrypted;
137 }
138}
139
140void mc_cipher_decrypt(MCCipher* cipher, u8* data, size_t size)
141{
142 size_t i;
143 for (i = 0; i < size; ++i) {
144 u8 encrypted = data[i];
145 data[i] ^= cipher_byte(cipher);
146 memmove(cipher->state, cipher->state + 1, 15);
147 cipher->state[15] = encrypted;
148 }
149}
150
151i8 mc_rsa_encrypt(const u8* public_key, size_t public_key_size, const u8* message, size_t message_size, u8** encrypted,
152 size_t* encrypted_size, char* error, size_t error_size)
153{
154 br_rsa_public_key key;
155 br_rsa_public rsa;
156 u8* output;
157 size_t padding_size;
158 size_t i;
159
160 if (!rsa_public_key(public_key, public_key_size, &key, error, error_size))
161 return 0;
162 if (message_size + 11 > key.nlen) {
163 mc_set_error(MC_EC_RSA_MESSAGE_TOO_LARGE, error, error_size, "message is too large for server RSA key");
164 return 0;
165 }
166 output = (u8*)malloc(key.nlen);
167 if (!output) {
168 mc_set_error(MC_EC_OUT_OF_MEMORY, error, error_size, "out of memory encrypting login response");
169 return 0;
170 }
171 padding_size = key.nlen - message_size - 3;
172 output[0] = 0;
173 output[1] = 2;
174 /* PKCS#1 v1.5 encryption padding requires every padding byte to be
175 nonzero */
176 if (!mg_random_bytes(output + 2, padding_size)) {
177 free(output);
178 mc_set_error(MC_EC_RANDOM, error, error_size, "could not obtain secure random bytes");
179 return 0;
180 }
181 for (i = 0; i < padding_size; ++i) {
182 while (output[2 + i] == 0) {
183 if (!mg_random_bytes(output + 2 + i, 1)) {
184 free(output);
185 mc_set_error(MC_EC_RANDOM, error, error_size, "could not obtain secure random bytes");
186 return 0;
187 }
188 }
189 }
190 output[2 + padding_size] = 0;
191 memcpy(output + 3 + padding_size, message, message_size);
192
193 rsa = br_rsa_public_get_default();
194 if (!rsa || !rsa(output, key.nlen, &key)) {
195 free(output);
196 mc_set_error(MC_EC_RSA_ENCRYPT, error, error_size, "BearSSL RSA encryption failed");
197 return 0;
198 }
199 *encrypted = output;
200 *encrypted_size = key.nlen;
201 return 1;
202}
203
204void mc_server_hash(const char* server_id, const u8 shared_secret[16], const u8* public_key, size_t public_key_size,
205 char output[42])
206{
207 static const char hex[] = "0123456789abcdef";
208 br_sha1_context sha;
209 u8 digest[20];
210 size_t first = 0;
211 size_t i;
212 size_t out = 0;
213 i8 negative;
214
215 br_sha1_init(&sha);
216 br_sha1_update(&sha, server_id, strlen(server_id));
217 br_sha1_update(&sha, shared_secret, 16);
218 br_sha1_update(&sha, public_key, public_key_size);
219 br_sha1_out(&sha, digest);
220 /* mc puts sha-1 digest as a signed twos-complement int */
221 negative = (digest[0] & 0x80) != 0;
222 if (negative)
223 twos_complement(digest, sizeof(digest));
224 while (first < sizeof(digest) && digest[first] == 0)
225 ++first;
226 if (negative)
227 output[out++] = '-';
228 if (first == sizeof(digest)) {
229 output[out++] = '0';
230 }
231 else {
232 output[out++] = hex[digest[first] >> 4];
233 output[out++] = hex[digest[first] & 15];
234 for (i = first + 1; i < sizeof(digest); ++i) {
235 output[out++] = hex[digest[i] >> 4];
236 output[out++] = hex[digest[i] & 15];
237 }
238 if (output[negative ? 1 : 0] == '0') {
239 memmove(output + (negative ? 1 : 0), output + (negative ? 2 : 1), out - (negative ? 2 : 1));
240 --out;
241 }
242 }
243 output[out] = '\0';
244}