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, UINT32* 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 UINT32 len = sizeof(dst->exponent);
101 BYTE* ptr = &dst->exponent[0];
102 if (!read_bignum(&ptr, &len, rsa_e, FALSE))
103 goto fail;
104 return TRUE;
105
106fail:
107 cert_info_free(dst);
108 return FALSE;
109}
110
111BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
112{
113 WINPR_ASSERT(dst);
114 WINPR_ASSERT(src);
115
116 *dst = *src;
117
118 dst->Modulus = NULL;
119 dst->ModulusLength = 0;
120 if (src->ModulusLength > 0)
121 {
122 dst->Modulus = malloc(src->ModulusLength);
123 if (!dst->Modulus)
124 return FALSE;
125 memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
126 dst->ModulusLength = src->ModulusLength;
127 }
128 return TRUE;
129}
130
131void cert_info_free(rdpCertInfo* info)
132{
133 WINPR_ASSERT(info);
134 free(info->Modulus);
135 info->ModulusLength = 0;
136 info->Modulus = NULL;
137}
138
139BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
140{
141 WINPR_ASSERT(info);
142 cert_info_free(info);
143
144 info->Modulus = (BYTE*)malloc(size);
145
146 if (!info->Modulus && (size > 0))
147 {
148 WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
149 return FALSE;
150 }
151 info->ModulusLength = (UINT32)size;
152 return TRUE;
153}
154
155BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
156{
157 if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
158 return FALSE;
159 if (size > UINT32_MAX)
160 {
161 WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
162 return FALSE;
163 }
164 if (!cert_info_allocate(info, size))
165 return FALSE;
166 Stream_Read(s, info->Modulus, info->ModulusLength);
167 return TRUE;
168}
169
170BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
171{
172 if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
173 return FALSE;
174 if (size > 4)
175 {
176 WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4);
177 return FALSE;
178 }
179 if (!info->Modulus || (info->ModulusLength == 0))
180 {
181 WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]", info->Modulus, info->ModulusLength);
182 return FALSE;
183 }
184 Stream_Read(s, &info->exponent[4 - size], size);
185 crypto_reverse(info->Modulus, info->ModulusLength);
186 crypto_reverse(info->exponent, 4);
187 return TRUE;
188}
189
190#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
191X509* x509_from_rsa(const RSA* rsa)
192{
193 EVP_PKEY* pubkey = NULL;
194 X509* x509 = NULL;
195 BIO* bio = BIO_new(
196#if defined(LIBRESSL_VERSION_NUMBER)
197 BIO_s_mem()
198#else
199 BIO_s_secmem()
200#endif
201 );
202 if (!bio)
203 {
204 WLog_ERR(TAG, "BIO_new() failed");
205 return NULL;
206 }
207
208 const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
209 if (rc != 1)
210 {
211 WLog_ERR(TAG, "PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa) failed");
212 goto fail;
213 }
214
215 pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
216 if (!pubkey)
217 {
218 WLog_ERR(TAG, "PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL) failed");
219 goto fail;
220 }
221
222 x509 = X509_new();
223 if (!x509)
224 {
225 WLog_ERR(TAG, "X509_new() failed");
226 goto fail;
227 }
228
229 const int res = X509_set_pubkey(x509, pubkey);
230 if (res != 1)
231 {
232 WLog_ERR(TAG, "X509_set_pubkey(x509, pubkey) failed");
233 X509_free(x509);
234 x509 = NULL;
235 goto fail;
236 }
237fail:
238 BIO_free_all(bio);
239 EVP_PKEY_free(pubkey);
240 return x509;
241}
242#endif