FreeRDP
Loading...
Searching...
No Matches
libfreerdp/crypto/crypto.c
1
22#include <errno.h>
23
24#include <openssl/objects.h>
25#include <openssl/bn.h>
26
27#include <freerdp/config.h>
28
29#include <winpr/crt.h>
30#include <winpr/assert.h>
31
32#include <freerdp/log.h>
33#include <freerdp/crypto/crypto.h>
34
35#include "crypto.h"
36#include "privatekey.h"
37
38#define TAG FREERDP_TAG("crypto")
39
40static SSIZE_T crypto_rsa_common(const BYTE* input, size_t length, UINT32 key_length,
41 const BYTE* modulus, const BYTE* exponent, size_t exponent_size,
42 BYTE* output, size_t out_length)
43{
44 BN_CTX* ctx = NULL;
45 int output_length = -1;
46 BYTE* input_reverse = NULL;
47 BYTE* modulus_reverse = NULL;
48 BYTE* exponent_reverse = NULL;
49 BIGNUM* mod = NULL;
50 BIGNUM* exp = NULL;
51 BIGNUM* x = NULL;
52 BIGNUM* y = NULL;
53 size_t bufferSize = 0;
54
55 if (!input || !modulus || !exponent || !output)
56 return -1;
57
58 if (exponent_size > INT_MAX / 2)
59 return -1;
60
61 if (key_length >= INT_MAX / 2 - exponent_size)
62 return -1;
63
64 bufferSize = 2ULL * key_length + exponent_size;
65 if (length > bufferSize)
66 bufferSize = length;
67
68 input_reverse = (BYTE*)calloc(bufferSize, 1);
69
70 if (!input_reverse)
71 return -1;
72
73 modulus_reverse = input_reverse + key_length;
74 exponent_reverse = modulus_reverse + key_length;
75 memcpy(modulus_reverse, modulus, key_length);
76 crypto_reverse(modulus_reverse, key_length);
77 memcpy(exponent_reverse, exponent, exponent_size);
78 crypto_reverse(exponent_reverse, exponent_size);
79 memcpy(input_reverse, input, length);
80 crypto_reverse(input_reverse, length);
81
82 if (!(ctx = BN_CTX_new()))
83 goto fail;
84
85 if (!(mod = BN_new()))
86 goto fail;
87
88 if (!(exp = BN_new()))
89 goto fail;
90
91 if (!(x = BN_new()))
92 goto fail;
93
94 if (!(y = BN_new()))
95 goto fail;
96
97 if (!BN_bin2bn(modulus_reverse, (int)key_length, mod))
98 goto fail;
99
100 if (!BN_bin2bn(exponent_reverse, (int)exponent_size, exp))
101 goto fail;
102 if (!BN_bin2bn(input_reverse, (int)length, x))
103 goto fail;
104 if (BN_mod_exp(y, x, exp, mod, ctx) != 1)
105 goto fail;
106 output_length = BN_bn2bin(y, output);
107 if (output_length < 0)
108 goto fail;
109 if (WINPR_ASSERTING_INT_CAST(size_t, output_length) > out_length)
110 goto fail;
111 crypto_reverse(output, WINPR_ASSERTING_INT_CAST(size_t, output_length));
112
113 if ((size_t)output_length < key_length)
114 {
115 size_t diff = key_length - WINPR_ASSERTING_INT_CAST(size_t, output_length);
116 if ((size_t)output_length + diff > out_length)
117 diff = out_length - (size_t)output_length;
118 memset(output + output_length, 0, diff);
119 }
120
121fail:
122 BN_free(y);
123 BN_clear_free(x);
124 BN_free(exp);
125 BN_free(mod);
126 BN_CTX_free(ctx);
127 free(input_reverse);
128 return output_length;
129}
130
131static SSIZE_T crypto_rsa_public(const BYTE* input, size_t length, const rdpCertInfo* cert,
132 BYTE* output, size_t output_length)
133{
134 WINPR_ASSERT(cert);
135 return crypto_rsa_common(input, length, cert->ModulusLength, cert->Modulus, cert->exponent,
136 sizeof(cert->exponent), output, output_length);
137}
138
139static SSIZE_T crypto_rsa_private(const BYTE* input, size_t length, const rdpPrivateKey* key,
140 BYTE* output, size_t output_length)
141{
142 WINPR_ASSERT(key);
143 const rdpCertInfo* info = freerdp_key_get_info(key);
144 WINPR_ASSERT(info);
145
146 size_t PrivateExponentLength = 0;
147 const BYTE* PrivateExponent = freerdp_key_get_exponent(key, &PrivateExponentLength);
148 return crypto_rsa_common(input, length, info->ModulusLength, info->Modulus, PrivateExponent,
149 PrivateExponentLength, output, output_length);
150}
151
152SSIZE_T crypto_rsa_public_encrypt(const BYTE* input, size_t length, const rdpCertInfo* cert,
153 BYTE* output, size_t output_length)
154{
155 return crypto_rsa_public(input, length, cert, output, output_length);
156}
157
158SSIZE_T crypto_rsa_public_decrypt(const BYTE* input, size_t length, const rdpCertInfo* cert,
159 BYTE* output, size_t output_length)
160{
161 return crypto_rsa_public(input, length, cert, output, output_length);
162}
163
164SSIZE_T crypto_rsa_private_encrypt(const BYTE* input, size_t length, const rdpPrivateKey* key,
165 BYTE* output, size_t output_length)
166{
167 return crypto_rsa_private(input, length, key, output, output_length);
168}
169
170SSIZE_T crypto_rsa_private_decrypt(const BYTE* input, size_t length, const rdpPrivateKey* key,
171 BYTE* output, size_t output_length)
172{
173 return crypto_rsa_private(input, length, key, output, output_length);
174}
175
176void crypto_reverse(BYTE* data, size_t length)
177{
178 if (length < 1)
179 return;
180
181 for (size_t i = 0, j = length - 1; i < j; i++, j--)
182 {
183 const BYTE temp = data[i];
184 data[i] = data[j];
185 data[j] = temp;
186 }
187}
188
189char* crypto_read_pem(const char* WINPR_RESTRICT filename, size_t* WINPR_RESTRICT plength)
190{
191 char* pem = NULL;
192 FILE* fp = NULL;
193
194 WINPR_ASSERT(filename);
195
196 if (plength)
197 *plength = 0;
198
199 fp = winpr_fopen(filename, "r");
200 if (!fp)
201 goto fail;
202 const int rs = _fseeki64(fp, 0, SEEK_END);
203 if (rs < 0)
204 goto fail;
205 const int64_t size = _ftelli64(fp);
206 if (size < 0)
207 goto fail;
208 const int rc = _fseeki64(fp, 0, SEEK_SET);
209 if (rc < 0)
210 goto fail;
211
212 pem = calloc(WINPR_ASSERTING_INT_CAST(size_t, size) + 1, sizeof(char));
213 if (!pem)
214 goto fail;
215
216 const size_t fr = fread(pem, (size_t)size, 1, fp);
217 if (fr != 1)
218 goto fail;
219
220 if (plength)
221 *plength = strnlen(pem, WINPR_ASSERTING_INT_CAST(size_t, size));
222 (void)fclose(fp);
223 return pem;
224
225fail:
226{
227 char buffer[8192] = { 0 };
228 WLog_WARN(TAG, "Failed to read PEM from file '%s' [%s]", filename,
229 winpr_strerror(errno, buffer, sizeof(buffer)));
230}
231 if (fp)
232 (void)fclose(fp);
233 free(pem);
234 return NULL;
235}
236
237BOOL crypto_write_pem(const char* WINPR_RESTRICT filename, const char* WINPR_RESTRICT pem,
238 size_t length)
239{
240 WINPR_ASSERT(filename);
241 WINPR_ASSERT(pem || (length == 0));
242
243 WINPR_ASSERT(filename);
244 WINPR_ASSERT(pem);
245
246 const size_t size = strnlen(pem, length) + 1;
247 size_t rc = 0;
248 FILE* fp = winpr_fopen(filename, "w");
249 if (!fp)
250 goto fail;
251 rc = fwrite(pem, 1, size, fp);
252 (void)fclose(fp);
253fail:
254 if (rc == 0)
255 {
256 char buffer[8192] = { 0 };
257 WLog_WARN(TAG, "Failed to write PEM [%" PRIuz "] to file '%s' [%s]", length, filename,
258 winpr_strerror(errno, buffer, sizeof(buffer)));
259 }
260 return rc == size;
261}