Coverage Report

Created: 2023-09-25 06:56

/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
40
#include "cert_common.h"
41
#include "crypto.h"
42
#include "opensslcompat.h"
43
44
#define TAG FREERDP_TAG("core")
45
46
static BOOL cert_info_allocate(rdpCertInfo* info, size_t size);
47
48
BOOL read_bignum(BYTE** dst, UINT32* length, const BIGNUM* num, BOOL alloc)
49
0
{
50
0
  WINPR_ASSERT(dst);
51
0
  WINPR_ASSERT(length);
52
0
  WINPR_ASSERT(num);
53
54
0
  if (alloc)
55
0
  {
56
0
    free(*dst);
57
0
    *dst = NULL;
58
0
    *length = 0;
59
0
  }
60
61
0
  const int len = BN_num_bytes(num);
62
0
  if (len < 0)
63
0
    return FALSE;
64
65
0
  if (!alloc)
66
0
  {
67
0
    if (*length < (UINT32)len)
68
0
      return FALSE;
69
0
  }
70
71
0
  if (len > 0)
72
0
  {
73
0
    if (alloc)
74
0
    {
75
0
      *dst = malloc((size_t)len);
76
0
      if (!*dst)
77
0
        return FALSE;
78
0
    }
79
0
    BN_bn2bin(num, *dst);
80
0
    crypto_reverse(*dst, (size_t)len);
81
0
    *length = (UINT32)len;
82
0
  }
83
84
0
  return TRUE;
85
0
}
86
87
BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e)
88
0
{
89
0
  const rdpCertInfo empty = { 0 };
90
91
0
  WINPR_ASSERT(dst);
92
0
  WINPR_ASSERT(rsa);
93
94
0
  *dst = empty;
95
96
0
  if (!read_bignum(&dst->Modulus, &dst->ModulusLength, rsa, TRUE))
97
0
    goto fail;
98
99
0
  UINT32 len = sizeof(dst->exponent);
100
0
  BYTE* ptr = &dst->exponent[0];
101
0
  if (!read_bignum(&ptr, &len, rsa_e, FALSE))
102
0
    goto fail;
103
0
  return TRUE;
104
105
0
fail:
106
0
  cert_info_free(dst);
107
0
  return FALSE;
108
0
}
109
110
BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
111
0
{
112
0
  WINPR_ASSERT(dst);
113
0
  WINPR_ASSERT(src);
114
115
0
  *dst = *src;
116
117
0
  dst->Modulus = NULL;
118
0
  dst->ModulusLength = 0;
119
0
  if (src->ModulusLength > 0)
120
0
  {
121
0
    dst->Modulus = malloc(src->ModulusLength);
122
0
    if (!dst->Modulus)
123
0
      return FALSE;
124
0
    memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
125
0
    dst->ModulusLength = src->ModulusLength;
126
0
  }
127
0
  return TRUE;
128
0
}
129
130
void cert_info_free(rdpCertInfo* info)
131
0
{
132
0
  WINPR_ASSERT(info);
133
0
  free(info->Modulus);
134
0
  info->ModulusLength = 0;
135
0
  info->Modulus = NULL;
136
0
}
137
138
BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
139
0
{
140
0
  WINPR_ASSERT(info);
141
0
  cert_info_free(info);
142
143
0
  info->Modulus = (BYTE*)malloc(size);
144
145
0
  if (!info->Modulus && (size > 0))
146
0
    return FALSE;
147
0
  info->ModulusLength = (UINT32)size;
148
0
  return TRUE;
149
0
}
150
151
BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
152
0
{
153
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
154
0
    return FALSE;
155
0
  if (size > UINT32_MAX)
156
0
    return FALSE;
157
0
  if (!cert_info_allocate(info, size))
158
0
    return FALSE;
159
0
  Stream_Read(s, info->Modulus, info->ModulusLength);
160
0
  return TRUE;
161
0
}
162
163
BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
164
0
{
165
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
166
0
    return FALSE;
167
0
  if (size > 4)
168
0
    return FALSE;
169
0
  if (!info->Modulus || (info->ModulusLength == 0))
170
0
    return FALSE;
171
0
  Stream_Read(s, &info->exponent[4 - size], size);
172
0
  crypto_reverse(info->Modulus, info->ModulusLength);
173
0
  crypto_reverse(info->exponent, 4);
174
0
  return TRUE;
175
0
}
176
177
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
178
X509* x509_from_rsa(const RSA* rsa)
179
0
{
180
0
  EVP_PKEY* pubkey = NULL;
181
0
  X509* x509 = NULL;
182
0
  BIO* bio = BIO_new(BIO_s_secmem());
183
0
  if (!bio)
184
0
    return NULL;
185
186
0
  const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
187
0
  if (rc != 1)
188
0
    goto fail;
189
190
0
  pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
191
0
  if (!pubkey)
192
0
    goto fail;
193
194
0
  x509 = X509_new();
195
0
  if (!x509)
196
0
    goto fail;
197
198
0
  const int res = X509_set_pubkey(x509, pubkey);
199
0
  if (res != 1)
200
0
  {
201
0
    X509_free(x509);
202
0
    x509 = NULL;
203
0
    goto fail;
204
0
  }
205
0
fail:
206
0
  BIO_free_all(bio);
207
0
  EVP_PKEY_free(pubkey);
208
0
  return x509;
209
0
}
210
#endif