FreeRDP
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 
47 static BOOL cert_info_allocate(rdpCertInfo* info, size_t size);
48 
49 BOOL 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 
88 BOOL 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 
106 fail:
107  cert_info_free(dst);
108  return FALSE;
109 }
110 
111 BOOL 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 
131 void cert_info_free(rdpCertInfo* info)
132 {
133  WINPR_ASSERT(info);
134  free(info->Modulus);
135  info->ModulusLength = 0;
136  info->Modulus = NULL;
137 }
138 
139 BOOL 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 
155 BOOL 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 
170 BOOL 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)
191 X509* 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  return NULL;
204 
205  const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
206  if (rc != 1)
207  goto fail;
208 
209  pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
210  if (!pubkey)
211  goto fail;
212 
213  x509 = X509_new();
214  if (!x509)
215  goto fail;
216 
217  const int res = X509_set_pubkey(x509, pubkey);
218  if (res != 1)
219  {
220  X509_free(x509);
221  x509 = NULL;
222  goto fail;
223  }
224 fail:
225  BIO_free_all(bio);
226  EVP_PKEY_free(pubkey);
227  return x509;
228 }
229 #endif