-
Notifications
You must be signed in to change notification settings - Fork 0
/
kssl_core.c
220 lines (181 loc) · 5.58 KB
/
kssl_core.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// kssl_core.c: Core APIs for CloudFlare Keyless SSL protocol
//
// Copyright (c) 2013 CloudFlare, Inc.
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "kssl.h"
#include "kssl_helpers.h"
#include "kssl_private_key.h"
#include "kssl_core.h"
extern int silent;
// Public functions
// kssl_operate: create a serialized response from a KSSL request
// header and payload
kssl_error_code kssl_operate(kssl_header *header,
BYTE *payload,
pk_list privates,
BYTE **out_response,
int *out_response_len)
{
kssl_error_code err = KSSL_ERROR_NONE;
BYTE *local_resp = NULL;
int local_resp_len = 0;
// Parse the indices of the items out of the payload
kssl_header out_header;
kssl_operation request;
kssl_operation response;
BYTE *out_payload = NULL;
zero_operation(&request);
zero_operation(&response);
*out_response = 0;
*out_response_len = 0;
// Extract the items from the payload
err = parse_message_payload(payload, header->length, &request);
if (err != KSSL_ERROR_NONE) {
goto exit;
}
if (silent == 0) {
log_operation(header, &request);
}
switch (request.opcode) {
// Other side sent response, error or pong: unexpected
case KSSL_OP_RESPONSE:
case KSSL_OP_ERROR:
case KSSL_OP_PONG:
{
err = KSSL_ERROR_UNEXPECTED_OPCODE;
break;
}
// Echo is trivial, it just echos the complete state->header back
// including the payload item
case KSSL_OP_PING:
{
response.is_payload_set = 1;
response.payload = request.payload;
response.payload_len = request.payload_len;
response.is_opcode_set = 1;
response.opcode = KSSL_OP_PONG;
break;
}
// Decrypt or sign the payload using the private key
case KSSL_OP_RSA_DECRYPT:
case KSSL_OP_RSA_DECRYPT_RAW:
case KSSL_OP_RSA_SIGN_MD5SHA1:
case KSSL_OP_RSA_SIGN_SHA1:
case KSSL_OP_RSA_SIGN_SHA224:
case KSSL_OP_RSA_SIGN_SHA256:
case KSSL_OP_RSA_SIGN_SHA384:
case KSSL_OP_RSA_SIGN_SHA512:
case KSSL_OP_ECDSA_SIGN_MD5SHA1:
case KSSL_OP_ECDSA_SIGN_SHA1:
case KSSL_OP_ECDSA_SIGN_SHA224:
case KSSL_OP_ECDSA_SIGN_SHA256:
case KSSL_OP_ECDSA_SIGN_SHA384:
case KSSL_OP_ECDSA_SIGN_SHA512:
{
unsigned int payload_size;
int max_payload_size;
int key_id;
if (request.is_ski_set) {
// Identify private key from request ski
key_id = find_private_key(privates, request.ski, NULL);
} else if (request.is_digest_set) {
key_id = find_private_key(privates, NULL, request.digest);
} else {
err = KSSL_ERROR_FORMAT;
break;
}
if (key_id < 0) {
err = KSSL_ERROR_KEY_NOT_FOUND;
break;
}
// Allocate buffer to hold output of private key operation
max_payload_size = key_size(privates, key_id);
out_payload = malloc(max_payload_size);
if (out_payload == NULL) {
err = KSSL_ERROR_INTERNAL;
break;
}
// Operate on payload
err = private_key_operation(privates, key_id, request.opcode,
request.payload_len, request.payload, out_payload,
&payload_size);
if (err != KSSL_ERROR_NONE) {
err = KSSL_ERROR_CRYPTO_FAILED;
break;
}
response.is_payload_set = 1;
response.payload = out_payload;
response.payload_len = payload_size;
response.is_opcode_set = 1;
response.opcode = KSSL_OP_RESPONSE;
break;
}
// This should not occur
default:
{
err = KSSL_ERROR_BAD_OPCODE;
break;
}
}
exit:
if (err != KSSL_ERROR_NONE) {
err = kssl_error(header->id, err, &local_resp, &local_resp_len);
} else {
// Create output header
out_header.version_maj = KSSL_VERSION_MAJ;
out_header.version_min = KSSL_VERSION_MIN;
out_header.id = header->id;
// Note that the response in &local_resp is dynamically allocated
// and needs to be freed
err = flatten_operation(&out_header, &response, &local_resp,
&local_resp_len);
}
free(out_payload);
if (err == KSSL_ERROR_NONE) {
*out_response = local_resp;
*out_response_len = local_resp_len;
}
return err;
}
// see core.h
kssl_error_code kssl_error(DWORD id,
BYTE error,
BYTE **response,
int *response_len)
{
kssl_header e;
int offset = 0;
int size = KSSL_HEADER_SIZE + KSSL_OPCODE_ITEM_SIZE + KSSL_ERROR_ITEM_SIZE;
BYTE *resp;
// The operation will always be padded to KSSL_PAD_TO +
// KSSL_ITEM_HEADER_SIZE bytes
int padding_size = 0;
if (size < KSSL_PAD_TO) {
padding_size = KSSL_PAD_TO - size;
}
if (response == NULL || response_len == NULL) {
return KSSL_ERROR_INTERNAL;
}
size += padding_size + KSSL_ITEM_HEADER_SIZE;
// The memory is calloced here to ensure that it is all zero. This is
// important because the padding added below is done by just adding a
// KSSL_ITEM at the end of the message stating that it has N bytes of
// padding.
resp = (BYTE *)calloc(size, 1);
if (resp == NULL) {
return KSSL_ERROR_INTERNAL;
}
e.version_maj = KSSL_VERSION_MAJ;
e.version_min = KSSL_VERSION_MIN;
e.length = size - KSSL_HEADER_SIZE;
e.id = id;
flatten_header(&e, resp, &offset);
flatten_item_byte(KSSL_TAG_OPCODE, KSSL_OP_ERROR, resp, &offset);
flatten_item_byte(KSSL_TAG_PAYLOAD, error, resp, &offset);
add_padding(padding_size, resp, &offset);
*response = resp;
*response_len = size;
return KSSL_ERROR_NONE;
}