24#include <openssl/objects.h>
25#include <openssl/bn.h>
27#include <freerdp/config.h>
30#include <winpr/assert.h>
32#include <freerdp/log.h>
33#include <freerdp/crypto/crypto.h>
36#include "privatekey.h"
42#define TAG FREERDP_TAG("crypto")
44static SSIZE_T crypto_rsa_common(
const BYTE* input,
size_t length, UINT32 key_length,
45 const BYTE* modulus,
const BYTE* exponent,
size_t exponent_size,
46 BYTE* output,
size_t out_length)
48 BN_CTX* ctx =
nullptr;
49 int output_length = -1;
50 BYTE* input_reverse =
nullptr;
51 BYTE* modulus_reverse =
nullptr;
52 BYTE* exponent_reverse =
nullptr;
53 BIGNUM* mod =
nullptr;
54 BIGNUM* exp =
nullptr;
57 size_t bufferSize = 0;
59 if (!input || !modulus || !exponent || !output)
62 if (exponent_size > INT_MAX / 2)
65 if (key_length >= INT_MAX / 2 - exponent_size)
68 bufferSize = 2ULL * key_length + exponent_size;
69 if (length > bufferSize)
72 input_reverse = (BYTE*)calloc(bufferSize, 1);
77 modulus_reverse = input_reverse + key_length;
78 exponent_reverse = modulus_reverse + key_length;
79 memmove(modulus_reverse, modulus, key_length);
80 crypto_reverse(modulus_reverse, key_length);
81 memmove(exponent_reverse, exponent, exponent_size);
82 crypto_reverse(exponent_reverse, exponent_size);
83 memmove(input_reverse, input, length);
84 crypto_reverse(input_reverse, length);
86 if (!(ctx = BN_CTX_new()))
89 if (!(mod = BN_new()))
92 if (!(exp = BN_new()))
101 if (!BN_bin2bn(modulus_reverse, (
int)key_length, mod))
104 if (!BN_bin2bn(exponent_reverse, (
int)exponent_size, exp))
106 if (!BN_bin2bn(input_reverse, (
int)length, x))
108 if (BN_mod_exp(y, x, exp, mod, ctx) != 1)
111 const int len = BN_num_bytes(y);
112 if ((len < 0) || (WINPR_ASSERTING_INT_CAST(
size_t, len) > out_length))
114 output_length = BN_bn2bin(y, output);
116 if (output_length < 0)
118 crypto_reverse(output, WINPR_ASSERTING_INT_CAST(
size_t, output_length));
120 if ((
size_t)output_length < key_length)
122 size_t diff = key_length - WINPR_ASSERTING_INT_CAST(
size_t, output_length);
123 if ((
size_t)output_length + diff > out_length)
124 diff = out_length - (size_t)output_length;
125 memset(output + output_length, 0, diff);
135 return output_length;
138static SSIZE_T crypto_rsa_public(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
139 BYTE* output,
size_t output_length)
142 return crypto_rsa_common(input, length, cert->ModulusLength, cert->Modulus, cert->exponent,
143 sizeof(cert->exponent), output, output_length);
146static SSIZE_T crypto_rsa_private(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
147 BYTE* output,
size_t output_length)
150 const rdpCertInfo* info = freerdp_key_get_info(key);
153 size_t PrivateExponentLength = 0;
154 const BYTE* PrivateExponent = freerdp_key_get_exponent(key, &PrivateExponentLength);
155 return crypto_rsa_common(input, length, info->ModulusLength, info->Modulus, PrivateExponent,
156 PrivateExponentLength, output, output_length);
159SSIZE_T crypto_rsa_public_encrypt(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
160 BYTE* output,
size_t output_length)
162 return crypto_rsa_public(input, length, cert, output, output_length);
165SSIZE_T crypto_rsa_public_decrypt(
const BYTE* input,
size_t length,
const rdpCertInfo* cert,
166 BYTE* output,
size_t output_length)
168 return crypto_rsa_public(input, length, cert, output, output_length);
171SSIZE_T crypto_rsa_private_encrypt(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
172 BYTE* output,
size_t output_length)
174 return crypto_rsa_private(input, length, key, output, output_length);
177SSIZE_T crypto_rsa_private_decrypt(
const BYTE* input,
size_t length,
const rdpPrivateKey* key,
178 BYTE* output,
size_t output_length)
180 return crypto_rsa_private(input, length, key, output, output_length);
183void crypto_reverse(BYTE* data,
size_t length)
188 for (
size_t i = 0, j = length - 1; i < j; i++, j--)
190 const BYTE temp = data[i];
196char* crypto_read_pem(
const char* WINPR_RESTRICT filename,
size_t* WINPR_RESTRICT plength)
201 WINPR_ASSERT(filename);
210 fp = winpr_fopen(filename,
"rb");
215 const int rs = _fseeki64(fp, 0, SEEK_END);
221 const int64_t size = _ftelli64(fp);
226 const int rc = _fseeki64(fp, 0, SEEK_SET);
231 pem = calloc(WINPR_ASSERTING_INT_CAST(
size_t, size) + 1,
sizeof(
char));
236 const size_t fr = fread(pem, (
size_t)size, 1, fp);
242 *plength = strnlen(pem, WINPR_ASSERTING_INT_CAST(
size_t, size));
249 char buffer[8192] = WINPR_C_ARRAY_INIT;
250 WLog_WARN(TAG,
"Failed to read PEM from file '%s' [%s]", filename,
251 winpr_strerror(errno, buffer,
sizeof(buffer)));
259BOOL crypto_write_pem(
const char* WINPR_RESTRICT filename,
const char* WINPR_RESTRICT pem,
262 WINPR_ASSERT(filename);
263 WINPR_ASSERT(pem || (length == 0));
265 WINPR_ASSERT(filename);
268 const size_t size = strnlen(pem, length) + 1;
270 FILE* fp = winpr_fopen(filename,
"w");
274 const int res = fchmod(fileno(fp), S_IRUSR | S_IWUSR);
277 char buffer[128] = WINPR_C_ARRAY_INIT;
278 WLog_WARN(TAG,
"Failed to chmod %s: %s", filename,
279 winpr_strerror(errno, buffer,
sizeof(buffer)));
280 const int fres = fclose(fp);
283 char buffer2[128] = WINPR_C_ARRAY_INIT;
284 WLog_WARN(TAG,
"Failed to close PEM [%" PRIuz
"] to file '%s' [%s]", length, filename,
285 winpr_strerror(errno, buffer2,
sizeof(buffer2)));
290 rc = fwrite(pem, 1, size, fp);
291 const int fres = fclose(fp);
294 char buffer[128] = WINPR_C_ARRAY_INIT;
295 WLog_WARN(TAG,
"Failed to close PEM [%" PRIuz
"] to file '%s' [%s]", length, filename,
296 winpr_strerror(errno, buffer,
sizeof(buffer)));
301 char buffer[128] = WINPR_C_ARRAY_INIT;
302 WLog_WARN(TAG,
"Failed to write PEM [%" PRIuz
"] to file '%s' [%s]", length, filename,
303 winpr_strerror(errno, buffer,
sizeof(buffer)));