Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/crypto/cert_common.c
Line
Count
Source (jump to first uncovered line)
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, UINT32* length, const BIGNUM* num, BOOL alloc)
50
66
{
51
66
  WINPR_ASSERT(dst);
52
66
  WINPR_ASSERT(length);
53
66
  WINPR_ASSERT(num);
54
55
66
  if (alloc)
56
33
  {
57
33
    free(*dst);
58
33
    *dst = NULL;
59
33
    *length = 0;
60
33
  }
61
62
66
  const int len = BN_num_bytes(num);
63
66
  if (len < 0)
64
0
    return FALSE;
65
66
66
  if (!alloc)
67
33
  {
68
33
    if (*length < (UINT32)len)
69
12
      return FALSE;
70
33
  }
71
72
54
  if (len > 0)
73
45
  {
74
45
    if (alloc)
75
30
    {
76
30
      *dst = malloc((size_t)len);
77
30
      if (!*dst)
78
0
        return FALSE;
79
30
    }
80
45
    BN_bn2bin(num, *dst);
81
45
    crypto_reverse(*dst, (size_t)len);
82
45
    *length = (UINT32)len;
83
45
  }
84
85
54
  return TRUE;
86
54
}
87
88
BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e)
89
33
{
90
33
  const rdpCertInfo empty = { 0 };
91
92
33
  WINPR_ASSERT(dst);
93
33
  WINPR_ASSERT(rsa);
94
95
33
  *dst = empty;
96
97
33
  if (!read_bignum(&dst->Modulus, &dst->ModulusLength, rsa, TRUE))
98
0
    goto fail;
99
100
33
  UINT32 len = sizeof(dst->exponent);
101
33
  BYTE* ptr = &dst->exponent[0];
102
33
  if (!read_bignum(&ptr, &len, rsa_e, FALSE))
103
12
    goto fail;
104
21
  return TRUE;
105
106
12
fail:
107
12
  cert_info_free(dst);
108
12
  return FALSE;
109
33
}
110
111
BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
112
14.9k
{
113
14.9k
  WINPR_ASSERT(dst);
114
14.9k
  WINPR_ASSERT(src);
115
116
14.9k
  *dst = *src;
117
118
14.9k
  dst->Modulus = NULL;
119
14.9k
  dst->ModulusLength = 0;
120
14.9k
  if (src->ModulusLength > 0)
121
0
  {
122
0
    dst->Modulus = malloc(src->ModulusLength);
123
0
    if (!dst->Modulus)
124
0
      return FALSE;
125
0
    memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
126
0
    dst->ModulusLength = src->ModulusLength;
127
0
  }
128
14.9k
  return TRUE;
129
14.9k
}
130
131
void cert_info_free(rdpCertInfo* info)
132
104k
{
133
104k
  WINPR_ASSERT(info);
134
104k
  free(info->Modulus);
135
104k
  info->ModulusLength = 0;
136
104k
  info->Modulus = NULL;
137
104k
}
138
139
BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
140
0
{
141
0
  WINPR_ASSERT(info);
142
0
  cert_info_free(info);
143
144
0
  info->Modulus = (BYTE*)malloc(size);
145
146
0
  if (!info->Modulus && (size > 0))
147
0
  {
148
0
    WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
149
0
    return FALSE;
150
0
  }
151
0
  info->ModulusLength = (UINT32)size;
152
0
  return TRUE;
153
0
}
154
155
BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
156
0
{
157
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
158
0
    return FALSE;
159
0
  if (size > UINT32_MAX)
160
0
  {
161
0
    WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
162
0
    return FALSE;
163
0
  }
164
0
  if (!cert_info_allocate(info, size))
165
0
    return FALSE;
166
0
  Stream_Read(s, info->Modulus, info->ModulusLength);
167
0
  return TRUE;
168
0
}
169
170
BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
171
0
{
172
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
173
0
    return FALSE;
174
0
  if (size > 4)
175
0
  {
176
0
    WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4);
177
0
    return FALSE;
178
0
  }
179
0
  if (!info->Modulus || (info->ModulusLength == 0))
180
0
  {
181
0
    WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]", info->Modulus, info->ModulusLength);
182
0
    return FALSE;
183
0
  }
184
0
  Stream_Read(s, &info->exponent[4 - size], size);
185
0
  crypto_reverse(info->Modulus, info->ModulusLength);
186
0
  crypto_reverse(info->exponent, 4);
187
0
  return TRUE;
188
0
}
189
190
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
191
X509* x509_from_rsa(const RSA* rsa)
192
0
{
193
0
  EVP_PKEY* pubkey = NULL;
194
0
  X509* x509 = NULL;
195
0
  BIO* bio = BIO_new(
196
#if defined(LIBRESSL_VERSION_NUMBER)
197
      BIO_s_mem()
198
#else
199
0
      BIO_s_secmem()
200
0
#endif
201
0
  );
202
0
  if (!bio)
203
0
    return NULL;
204
205
0
  const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
206
0
  if (rc != 1)
207
0
    goto fail;
208
209
0
  pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
210
0
  if (!pubkey)
211
0
    goto fail;
212
213
0
  x509 = X509_new();
214
0
  if (!x509)
215
0
    goto fail;
216
217
0
  const int res = X509_set_pubkey(x509, pubkey);
218
0
  if (res != 1)
219
0
  {
220
0
    X509_free(x509);
221
0
    x509 = NULL;
222
0
    goto fail;
223
0
  }
224
0
fail:
225
0
  BIO_free_all(bio);
226
0
  EVP_PKEY_free(pubkey);
227
0
  return x509;
228
0
}
229
#endif