FreeRDP
Loading...
Searching...
No Matches
cert_common.c
1
25#include <freerdp/config.h>
26
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
30
31#include <winpr/assert.h>
32#include <winpr/wtypes.h>
33#include <winpr/crt.h>
34#include <winpr/file.h>
35#include <winpr/crypto.h>
36
37#include <openssl/pem.h>
38#include <openssl/rsa.h>
39#include <openssl/bn.h>
40
41#include "cert_common.h"
42#include "crypto.h"
43#include "opensslcompat.h"
44
45#define TAG FREERDP_TAG("core")
46
47static BOOL cert_info_allocate(rdpCertInfo* info, size_t size);
48
49BOOL read_bignum(BYTE** dst, DWORD* length, const BIGNUM* num, BOOL alloc)
50{
51 WINPR_ASSERT(dst);
52 WINPR_ASSERT(length);
53 WINPR_ASSERT(num);
54
55 if (alloc)
56 {
57 free(*dst);
58 *dst = NULL;
59 *length = 0;
60 }
61
62 const int len = BN_num_bytes(num);
63 if (len < 0)
64 return FALSE;
65
66 if (!alloc)
67 {
68 if (*length < (UINT32)len)
69 return FALSE;
70 }
71
72 if (len > 0)
73 {
74 if (alloc)
75 {
76 *dst = malloc((size_t)len);
77 if (!*dst)
78 return FALSE;
79 }
80 BN_bn2bin(num, *dst);
81 crypto_reverse(*dst, (size_t)len);
82 *length = (UINT32)len;
83 }
84
85 return TRUE;
86}
87
88BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e)
89{
90 const rdpCertInfo empty = { 0 };
91
92 WINPR_ASSERT(dst);
93 WINPR_ASSERT(rsa);
94
95 *dst = empty;
96
97 if (!read_bignum(&dst->Modulus, &dst->ModulusLength, rsa, TRUE))
98 goto fail;
99
100 {
101 DWORD len = sizeof(dst->exponent);
102 BYTE* ptr = &dst->exponent[0];
103 if (!read_bignum(&ptr, &len, rsa_e, FALSE))
104 goto fail;
105 }
106 return TRUE;
107
108fail:
109 cert_info_free(dst);
110 return FALSE;
111}
112
113BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
114{
115 WINPR_ASSERT(dst);
116 WINPR_ASSERT(src);
117
118 *dst = *src;
119
120 dst->Modulus = NULL;
121 dst->ModulusLength = 0;
122 if (src->ModulusLength > 0)
123 {
124 dst->Modulus = malloc(src->ModulusLength);
125 if (!dst->Modulus)
126 return FALSE;
127 memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
128 dst->ModulusLength = src->ModulusLength;
129 }
130 return TRUE;
131}
132
133void cert_info_free(rdpCertInfo* info)
134{
135 WINPR_ASSERT(info);
136 free(info->Modulus);
137 info->ModulusLength = 0;
138 info->Modulus = NULL;
139}
140
141BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
142{
143 WINPR_ASSERT(info);
144 cert_info_free(info);
145
146 info->Modulus = (BYTE*)malloc(size);
147
148 if (!info->Modulus && (size > 0))
149 {
150 WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
151 return FALSE;
152 }
153 info->ModulusLength = (UINT32)size;
154 return TRUE;
155}
156
157BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
158{
159 if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
160 return FALSE;
161 if (size > UINT32_MAX)
162 {
163 WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
164 return FALSE;
165 }
166 if (!cert_info_allocate(info, size))
167 return FALSE;
168 Stream_Read(s, info->Modulus, info->ModulusLength);
169 return TRUE;
170}
171
172BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
173{
174 if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
175 return FALSE;
176 if (size > 4)
177 {
178 WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4);
179 return FALSE;
180 }
181 if (!info->Modulus || (info->ModulusLength == 0))
182 {
183 WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]", info->Modulus, info->ModulusLength);
184 return FALSE;
185 }
186 Stream_Read(s, &info->exponent[4 - size], size);
187 crypto_reverse(info->Modulus, info->ModulusLength);
188 crypto_reverse(info->exponent, 4);
189 return TRUE;
190}
191
192#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
193X509* x509_from_rsa(const RSA* rsa)
194{
195 EVP_PKEY* pubkey = NULL;
196 X509* x509 = NULL;
197 BIO* bio = BIO_new(
198#if defined(LIBRESSL_VERSION_NUMBER)
199 BIO_s_mem()
200#else
201 BIO_s_secmem()
202#endif
203 );
204 if (!bio)
205 {
206 WLog_ERR(TAG, "BIO_new() failed");
207 return NULL;
208 }
209
210 const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
211 if (rc != 1)
212 {
213 WLog_ERR(TAG, "PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa) failed");
214 goto fail;
215 }
216
217 pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
218 if (!pubkey)
219 {
220 WLog_ERR(TAG, "PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL) failed");
221 goto fail;
222 }
223
224 x509 = X509_new();
225 if (!x509)
226 {
227 WLog_ERR(TAG, "X509_new() failed");
228 goto fail;
229 }
230
231 const int res = X509_set_pubkey(x509, pubkey);
232 if (res != 1)
233 {
234 WLog_ERR(TAG, "X509_set_pubkey(x509, pubkey) failed");
235 X509_free(x509);
236 x509 = NULL;
237 goto fail;
238 }
239fail:
240 BIO_free_all(bio);
241 EVP_PKEY_free(pubkey);
242 return x509;
243}
244#endif