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, 4u);
179 return FALSE;
180 }
181 if (!info->Modulus || (info->ModulusLength == 0))
182 {
183 WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]",
184 WINPR_CXX_COMPAT_CAST(const void*, info->Modulus), info->ModulusLength);
185 return FALSE;
186 }
187 Stream_Read(s, &info->exponent[4 - size], size);
188 crypto_reverse(info->Modulus, info->ModulusLength);
189 crypto_reverse(info->exponent, 4);
190 return TRUE;
191}
192
193#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
194X509* x509_from_rsa(const RSA* rsa)
195{
196 EVP_PKEY* pubkey = NULL;
197 X509* x509 = NULL;
198 BIO* bio = BIO_new(
199#if defined(LIBRESSL_VERSION_NUMBER)
200 BIO_s_mem()
201#else
202 BIO_s_secmem()
203#endif
204 );
205 if (!bio)
206 {
207 WLog_ERR(TAG, "BIO_new() failed");
208 return NULL;
209 }
210
211 const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
212 if (rc != 1)
213 {
214 WLog_ERR(TAG, "PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa) failed");
215 goto fail;
216 }
217
218 pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
219 if (!pubkey)
220 {
221 WLog_ERR(TAG, "PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL) failed");
222 goto fail;
223 }
224
225 x509 = X509_new();
226 if (!x509)
227 {
228 WLog_ERR(TAG, "X509_new() failed");
229 goto fail;
230 }
231
232 const int res = X509_set_pubkey(x509, pubkey);
233 if (res != 1)
234 {
235 WLog_ERR(TAG, "X509_set_pubkey(x509, pubkey) failed");
236 X509_free(x509);
237 x509 = NULL;
238 goto fail;
239 }
240fail:
241 BIO_free_all(bio);
242 EVP_PKEY_free(pubkey);
243 return x509;
244}
245#endif