Coverage Report

Created: 2026-01-09 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/crypto/cert_common.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Certificate Handling
4
 *
5
 * Copyright 2011 Jiten Pathy
6
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 * Copyright 2023 Armin Novak <anovak@thincast.com>
10
 * Copyright 2023 Thincast Technologies GmbH
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 *     http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24
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, DWORD* length, const BIGNUM* num, BOOL alloc)
50
0
{
51
0
  WINPR_ASSERT(dst);
52
0
  WINPR_ASSERT(length);
53
0
  WINPR_ASSERT(num);
54
55
0
  if (alloc)
56
0
  {
57
0
    free(*dst);
58
0
    *dst = NULL;
59
0
    *length = 0;
60
0
  }
61
62
0
  const int len = BN_num_bytes(num);
63
0
  if (len < 0)
64
0
    return FALSE;
65
66
0
  if (!alloc)
67
0
  {
68
0
    if (*length < (UINT32)len)
69
0
      return FALSE;
70
0
  }
71
72
0
  if (len > 0)
73
0
  {
74
0
    if (alloc)
75
0
    {
76
0
      *dst = malloc((size_t)len);
77
0
      if (!*dst)
78
0
        return FALSE;
79
0
    }
80
0
    BN_bn2bin(num, *dst);
81
0
    crypto_reverse(*dst, (size_t)len);
82
0
    *length = (UINT32)len;
83
0
  }
84
85
0
  return TRUE;
86
0
}
87
88
BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e)
89
0
{
90
0
  const rdpCertInfo empty = { 0 };
91
92
0
  WINPR_ASSERT(dst);
93
0
  WINPR_ASSERT(rsa);
94
95
0
  *dst = empty;
96
97
0
  if (!read_bignum(&dst->Modulus, &dst->ModulusLength, rsa, TRUE))
98
0
    goto fail;
99
100
0
  {
101
0
    DWORD len = sizeof(dst->exponent);
102
0
    BYTE* ptr = &dst->exponent[0];
103
0
    if (!read_bignum(&ptr, &len, rsa_e, FALSE))
104
0
      goto fail;
105
0
  }
106
0
  return TRUE;
107
108
0
fail:
109
0
  cert_info_free(dst);
110
0
  return FALSE;
111
0
}
112
113
BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
114
0
{
115
0
  WINPR_ASSERT(dst);
116
0
  WINPR_ASSERT(src);
117
118
0
  *dst = *src;
119
120
0
  dst->Modulus = NULL;
121
0
  dst->ModulusLength = 0;
122
0
  if (src->ModulusLength > 0)
123
0
  {
124
0
    dst->Modulus = malloc(src->ModulusLength);
125
0
    if (!dst->Modulus)
126
0
      return FALSE;
127
0
    memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
128
0
    dst->ModulusLength = src->ModulusLength;
129
0
  }
130
0
  return TRUE;
131
0
}
132
133
void cert_info_free(rdpCertInfo* info)
134
0
{
135
0
  WINPR_ASSERT(info);
136
0
  free(info->Modulus);
137
0
  info->ModulusLength = 0;
138
0
  info->Modulus = NULL;
139
0
}
140
141
BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
142
0
{
143
0
  WINPR_ASSERT(info);
144
0
  cert_info_free(info);
145
146
0
  info->Modulus = (BYTE*)malloc(size);
147
148
0
  if (!info->Modulus && (size > 0))
149
0
  {
150
0
    WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
151
0
    return FALSE;
152
0
  }
153
0
  info->ModulusLength = (UINT32)size;
154
0
  return TRUE;
155
0
}
156
157
BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
158
0
{
159
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
160
0
    return FALSE;
161
0
  if (size > UINT32_MAX)
162
0
  {
163
0
    WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
164
0
    return FALSE;
165
0
  }
166
0
  if (!cert_info_allocate(info, size))
167
0
    return FALSE;
168
0
  Stream_Read(s, info->Modulus, info->ModulusLength);
169
0
  return TRUE;
170
0
}
171
172
BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
173
0
{
174
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
175
0
    return FALSE;
176
0
  if (size > 4)
177
0
  {
178
0
    WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4);
179
0
    return FALSE;
180
0
  }
181
0
  if (!info->Modulus || (info->ModulusLength == 0))
182
0
  {
183
0
    WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]", info->Modulus, info->ModulusLength);
184
0
    return FALSE;
185
0
  }
186
0
  Stream_Read(s, &info->exponent[4 - size], size);
187
0
  crypto_reverse(info->Modulus, info->ModulusLength);
188
0
  crypto_reverse(info->exponent, 4);
189
0
  return TRUE;
190
0
}
191
192
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
193
X509* x509_from_rsa(const RSA* rsa)
194
0
{
195
0
  EVP_PKEY* pubkey = NULL;
196
0
  X509* x509 = NULL;
197
0
  BIO* bio = BIO_new(
198
#if defined(LIBRESSL_VERSION_NUMBER)
199
      BIO_s_mem()
200
#else
201
0
      BIO_s_secmem()
202
0
#endif
203
0
  );
204
0
  if (!bio)
205
0
  {
206
0
    WLog_ERR(TAG, "BIO_new() failed");
207
0
    return NULL;
208
0
  }
209
210
0
  const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
211
0
  if (rc != 1)
212
0
  {
213
0
    WLog_ERR(TAG, "PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa) failed");
214
0
    goto fail;
215
0
  }
216
217
0
  pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
218
0
  if (!pubkey)
219
0
  {
220
0
    WLog_ERR(TAG, "PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL) failed");
221
0
    goto fail;
222
0
  }
223
224
0
  x509 = X509_new();
225
0
  if (!x509)
226
0
  {
227
0
    WLog_ERR(TAG, "X509_new() failed");
228
0
    goto fail;
229
0
  }
230
231
0
  const int res = X509_set_pubkey(x509, pubkey);
232
0
  if (res != 1)
233
0
  {
234
0
    WLog_ERR(TAG, "X509_set_pubkey(x509, pubkey) failed");
235
0
    X509_free(x509);
236
0
    x509 = NULL;
237
0
    goto fail;
238
0
  }
239
0
fail:
240
0
  BIO_free_all(bio);
241
0
  EVP_PKEY_free(pubkey);
242
0
  return x509;
243
0
}
244
#endif