VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/ssl-openssl.cpp@ 96763

Last change on this file since 96763 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1/** @file
2 * IPRT - Crypto - Secure Socket Layer (SSL) / Transport Security Layer (TLS).
3 */
4
5/*
6 * Copyright (C) 2018-2022 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35#ifdef IPRT_WITH_OPENSSL /* whole file */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41# include "internal/iprt.h"
42# include <iprt/crypto/ssl.h>
43
44# include <iprt/asm.h>
45# include <iprt/assert.h>
46# include <iprt/err.h>
47# include <iprt/file.h>
48# include <iprt/mem.h>
49# include <iprt/string.h>
50
51# include "internal/magics.h"
52
53# include "internal/iprt-openssl.h"
54# include "internal/openssl-pre.h"
55# include <openssl/ssl.h>
56# include <openssl/tls1.h>
57# include "internal/openssl-post.h"
58
59
60/*********************************************************************************************************************************
61* Header Files *
62*********************************************************************************************************************************/
63/**
64 * SSL instance data for OpenSSL.
65 */
66typedef struct RTCRSSLINT
67{
68 /** Magic value (RTCRSSLINT_MAGIC). */
69 uint32_t u32Magic;
70 /** Reference count. */
71 uint32_t volatile cRefs;
72 /** The SSL context. */
73 SSL_CTX *pCtx;
74} RTCRSSLINT;
75
76/**
77 * SSL session instance data for OpenSSL.
78 */
79typedef struct RTCRSSLSESSIONINT
80{
81 /** Magic value (RTCRSSLSESSIONINT_MAGIC). */
82 uint32_t u32Magic;
83 /** Reference count. */
84 uint32_t volatile cRefs;
85 /** RTCRSSLSESSION_F_XXX. */
86 uint32_t fFlags;
87
88 /** The SSL instance. */
89 SSL *pSsl;
90 /** The socket BIO instance. */
91 BIO *pBio;
92} RTCRSSLSESSIONINT;
93
94
95
96RTDECL(int) RTCrSslCreate(PRTCRSSL phSsl, uint32_t fFlags)
97{
98 AssertPtr(phSsl);
99 *phSsl = NIL_RTCRSSL;
100 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
101
102 SSL_library_init();
103
104 /*
105 * We aim at TLSv1 or higher here by default.
106 */
107# if OPENSSL_VERSION_NUMBER >= 0x10100000
108 const SSL_METHOD *pSslMethod = TLS_method();
109# elif OPENSSL_VERSION_NUMBER >= 0x10002000
110 const SSL_METHOD *pSslMethod = SSLv23_method();
111# elif OPENSSL_VERSION_NUMBER >= 0x10000000
112 const SSL_METHOD *pSslMethod = TLSv1_method();
113# else
114 SSL_METHOD *pSslMethod = TLSv1_method();
115# endif
116 if (pSslMethod)
117 {
118 RTCRSSLINT *pThis = (RTCRSSLINT *)RTMemAllocZ(sizeof(*pThis));
119 if (pThis)
120 {
121 pThis->pCtx = SSL_CTX_new(pSslMethod);
122 if (pThis->pCtx)
123 {
124 /* Help with above aim. */
125# if OPENSSL_VERSION_NUMBER >= 0x10100000
126# ifndef SSL_CTX_get_min_proto_version
127/* Some older OpenSSL 1.1.0 releases lack the getters, officially they were
128 * added with 1.1.1 but someone cherry picked them, just maybe too late. */
129# define SSL_CTX_get_min_proto_version(ctx) (0)
130# endif
131 if (SSL_CTX_get_min_proto_version(pThis->pCtx) < TLS1_VERSION)
132 SSL_CTX_set_min_proto_version(pThis->pCtx, TLS1_VERSION);
133# elif OPENSSL_VERSION_NUMBER >= 0x10002000
134 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv2);
135 SSL_CTX_set_options(pThis->pCtx, SSL_OP_NO_SSLv3);
136# endif
137
138 /*
139 * Complete the instance and return it.
140 */
141 pThis->u32Magic = RTCRSSLINT_MAGIC;
142 pThis->cRefs = 1;
143
144 *phSsl = pThis;
145 return VINF_SUCCESS;
146 }
147
148 RTMemFree(pThis);
149 }
150 return VERR_NO_MEMORY;
151 }
152 return VERR_NOT_SUPPORTED;
153}
154
155
156RTDECL(uint32_t) RTCrSslRetain(RTCRSSL hSsl)
157{
158 RTCRSSLINT *pThis = hSsl;
159 AssertPtrReturn(pThis, UINT32_MAX);
160 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
161
162 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
163 Assert(cRefs > 1);
164 Assert(cRefs < 1024);
165 return cRefs;
166}
167
168
169/**
170 * Worker for RTCrSslRelease.
171 */
172static int rtCrSslDestroy(RTCRSSLINT *pThis)
173{
174 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLINT_MAGIC);
175 SSL_CTX_free(pThis->pCtx);
176 pThis->pCtx = NULL;
177 RTMemFree(pThis);
178 return 0;
179}
180
181
182RTDECL(uint32_t) RTCrSslRelease(RTCRSSL hSsl)
183{
184 RTCRSSLINT *pThis = hSsl;
185 if (pThis == NIL_RTCRSSL)
186 return 0;
187 AssertPtrReturn(pThis, UINT32_MAX);
188 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, UINT32_MAX);
189
190 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
191 Assert(cRefs < 1024);
192 if (cRefs == 0)
193 return rtCrSslDestroy(pThis);
194 return cRefs;
195}
196
197
198RTDECL(int) RTCrSslSetCertificateFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
199{
200 RTCRSSLINT *pThis = hSsl;
201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
202 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
203 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
204
205 int rcOssl = SSL_CTX_use_certificate_file(pThis->pCtx, pszFile,
206 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
207 if (rcOssl != 0)
208 return VINF_SUCCESS;
209 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
210}
211
212
213RTDECL(int) RTCrSslSetPrivateKeyFile(RTCRSSL hSsl, const char *pszFile, uint32_t fFlags)
214{
215 RTCRSSLINT *pThis = hSsl;
216 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
217 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
218 AssertReturn(!(fFlags & ~RTCRSSL_FILE_F_ASN1), VERR_INVALID_FLAGS);
219
220 int rcOssl = SSL_CTX_use_PrivateKey_file(pThis->pCtx, pszFile,
221 RTCRSSL_FILE_F_ASN1 & fFlags ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM);
222 if (rcOssl != 0)
223 return VINF_SUCCESS;
224 return !pszFile || !*pszFile || !RTFileExists(pszFile) ? VERR_FILE_NOT_FOUND : VERR_OPEN_FAILED; /** @todo Better status codes */
225}
226
227
228RTDECL(int) RTCrSslLoadTrustedRootCerts(RTCRSSL hSsl, const char *pszFile, const char *pszDir)
229{
230 RTCRSSLINT *pThis = hSsl;
231 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
232 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
233
234 int rcOssl = SSL_CTX_load_verify_locations(pThis->pCtx, pszFile, pszDir);
235 if (rcOssl != 0)
236 return VINF_SUCCESS;
237
238 if (!pszFile || !*pszFile || !RTFileExists(pszFile))
239 return VERR_FILE_NOT_FOUND;
240 return VERR_OPEN_FAILED; /** @todo Better status codes */
241}
242
243
244RTDECL(int) RTCrSslSetNoPeerVerify(RTCRSSL hSsl)
245{
246 RTCRSSLINT *pThis = hSsl;
247 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
248 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
249
250 SSL_CTX_set_verify(pThis->pCtx, SSL_VERIFY_NONE, NULL);
251 return VINF_SUCCESS;
252}
253
254
255
256//RTDECL(int) RTCrSslCreateSession(RTCRSSL hSsl, RTSOCKET hSocket, uint32_t fFlags, PRTCRSSLSESSION phSslConn);
257
258RTDECL(int) RTCrSslCreateSessionForNativeSocket(RTCRSSL hSsl, RTHCINTPTR hNativeSocket, uint32_t fFlags,
259 PRTCRSSLSESSION phSslSession)
260{
261 /*
262 * Validate input.
263 */
264 *phSslSession = NIL_RTCRSSLSESSION;
265
266 RTCRSSLINT *pThis = hSsl;
267 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
268 AssertReturn(pThis->u32Magic == RTCRSSLINT_MAGIC, VERR_INVALID_HANDLE);
269 AssertReturn(!(fFlags & ~RTCRSSLSESSION_F_NON_BLOCKING), VERR_INVALID_FLAGS);
270
271 /*
272 * Create a new session.
273 */
274 int rc = VERR_NO_MEMORY;
275 RTCRSSLSESSIONINT *pSession = (RTCRSSLSESSIONINT *)RTMemAllocZ(sizeof(*pSession));
276 if (pSession)
277 {
278 pSession->pSsl = SSL_new(pThis->pCtx);
279 if (pSession->pSsl)
280 {
281 /* Disable read-ahead if non-blocking socket relying on select/poll. */
282 if (fFlags & RTCRSSLSESSION_F_NON_BLOCKING)
283 SSL_set_read_ahead(pSession->pSsl, 0);
284
285 /* Create a wrapper for the socket handle. */
286 pSession->pBio = BIO_new_socket(hNativeSocket, BIO_NOCLOSE);
287 if (pSession->pBio)
288 {
289# if (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)) || LIBRESSL_VERSION_NUMBER >= 0x2070000f
290 BIO_up_ref(pSession->pBio); /* our reference. */
291# endif
292 SSL_set_bio(pSession->pSsl, pSession->pBio, pSession->pBio);
293
294 /*
295 * Done.
296 */
297 pSession->cRefs = 1;
298 pSession->u32Magic = RTCRSSLSESSIONINT_MAGIC;
299 *phSslSession = pSession;
300 return VINF_SUCCESS;
301 }
302
303 SSL_free(pSession->pSsl);
304 pSession->pSsl = NULL;
305 }
306 RTMemFree(pSession);
307 }
308 return rc;
309}
310
311
312/*********************************************************************************************************************************
313* Session implementation. *
314*********************************************************************************************************************************/
315
316RTDECL(uint32_t) RTCrSslSessionRetain(RTCRSSLSESSION hSslSession)
317{
318 RTCRSSLSESSIONINT *pThis = hSslSession;
319 AssertPtrReturn(pThis, UINT32_MAX);
320 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
321
322 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
323 Assert(cRefs > 1);
324 Assert(cRefs < 1024);
325 return cRefs;
326}
327
328
329/**
330 * Worker for RTCrSslRelease.
331 */
332static int rtCrSslSessionDestroy(RTCRSSLSESSIONINT *pThis)
333{
334 ASMAtomicWriteU32(&pThis->u32Magic, ~RTCRSSLSESSIONINT_MAGIC);
335 SSL_free(pThis->pSsl);
336 pThis->pSsl = NULL;
337# if (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)) || LIBRESSL_VERSION_NUMBER >= 0x2070000f
338 BIO_free(pThis->pBio);
339# endif
340 pThis->pBio = NULL;
341 RTMemFree(pThis);
342 return 0;
343}
344
345
346RTDECL(uint32_t) RTCrSslSessionRelease(RTCRSSLSESSION hSslSession)
347{
348 RTCRSSLSESSIONINT *pThis = hSslSession;
349 if (pThis == NIL_RTCRSSLSESSION)
350 return 0;
351 AssertPtrReturn(pThis, UINT32_MAX);
352 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, UINT32_MAX);
353
354 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
355 Assert(cRefs < 1024);
356 if (cRefs == 0)
357 return rtCrSslSessionDestroy(pThis);
358 return cRefs;
359}
360
361
362RTDECL(int) RTCrSslSessionAccept(RTCRSSLSESSION hSslSession, uint32_t fFlags)
363{
364 RTCRSSLSESSIONINT *pThis = hSslSession;
365 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
366 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
367 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
368
369 int rcOssl = SSL_accept(pThis->pSsl);
370 if (rcOssl > 0)
371 return VINF_SUCCESS;
372
373 /** @todo better status codes. */
374 if (BIO_should_retry(pThis->pBio))
375 return VERR_TRY_AGAIN;
376 return VERR_NOT_SUPPORTED;
377}
378
379
380RTDECL(int) RTCrSslSessionConnect(RTCRSSLSESSION hSslSession, uint32_t fFlags)
381{
382 RTCRSSLSESSIONINT *pThis = hSslSession;
383 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
384 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
385 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
386
387 int rcOssl = SSL_connect(pThis->pSsl);
388 if (rcOssl > 0)
389 return VINF_SUCCESS;
390
391 /** @todo better status codes. */
392 if (BIO_should_retry(pThis->pBio))
393 return VERR_TRY_AGAIN;
394 return VERR_NOT_SUPPORTED;
395}
396
397
398RTDECL(const char *) RTCrSslSessionGetVersion(RTCRSSLSESSION hSslSession)
399{
400 RTCRSSLSESSIONINT *pThis = hSslSession;
401 AssertPtrReturn(pThis, NULL);
402 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, NULL);
403
404 return SSL_get_version(pThis->pSsl);
405}
406
407
408RTDECL(int) RTCrSslSessionGetCertIssuerNameAsString(RTCRSSLSESSION hSslSession, char *pszBuf, size_t cbBuf, size_t *pcbActual)
409{
410 RTCRSSLSESSIONINT *pThis = hSslSession;
411 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
412 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
413 AssertPtrNull(pszBuf);
414 AssertPtrNull(pcbActual);
415 if (pcbActual)
416 *pcbActual = 0;
417
418 /*
419 * Get and format the certificate issuer name.
420 */
421 int rc = VERR_NOT_AVAILABLE;
422 X509 *pCert = SSL_get_certificate(pThis->pSsl);
423 if (pCert)
424 {
425 X509_NAME *pIssuer = X509_get_issuer_name(pCert);
426 if (pIssuer)
427 {
428 char *pszSrc = X509_NAME_oneline(pIssuer, NULL, 0);
429 if (pszSrc)
430 {
431 /*
432 * Copy out the result and free it.
433 */
434 size_t cbNeeded = strlen(pszSrc) + 1;
435 if (pcbActual)
436 *pcbActual = cbNeeded;
437
438 if (pszBuf != NULL && cbBuf > 0)
439 {
440 if (cbBuf >= cbNeeded)
441 {
442 memcpy(pszBuf, pszSrc, cbNeeded);
443 rc = VINF_SUCCESS;
444 }
445 else
446 {
447 memcpy(pszBuf, pszSrc, cbBuf - 1);
448 pszBuf[cbBuf - 1] = '\0';
449 rc = VERR_BUFFER_OVERFLOW;
450 }
451 }
452 else
453 rc = VERR_BUFFER_OVERFLOW;
454 OPENSSL_free(pszSrc);
455 }
456 }
457 }
458 return rc;
459}
460
461
462RTDECL(bool) RTCrSslSessionPending(RTCRSSLSESSION hSslSession)
463{
464 RTCRSSLSESSIONINT *pThis = hSslSession;
465 AssertPtrReturn(pThis, true);
466 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, true);
467
468 return SSL_pending(pThis->pSsl) != 0;
469}
470
471
472RTDECL(ssize_t) RTCrSslSessionRead(RTCRSSLSESSION hSslSession, void *pvBuf, size_t cbToRead)
473{
474 RTCRSSLSESSIONINT *pThis = hSslSession;
475 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
476 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
477
478 Assert((size_t)(int)cbToRead == cbToRead);
479
480 int cbActual = SSL_read(pThis->pSsl, pvBuf, (int)cbToRead);
481 if (cbActual > 0)
482 return cbActual;
483 if (BIO_should_retry(pThis->pBio))
484 return VERR_TRY_AGAIN;
485 return VERR_READ_ERROR; /** @todo better status codes. */
486}
487
488
489RTDECL(ssize_t) RTCrSslSessionWrite(RTCRSSLSESSION hSslSession, void const *pvBuf, size_t cbToWrite)
490{
491 RTCRSSLSESSIONINT *pThis = hSslSession;
492 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
493 AssertReturn(pThis->u32Magic == RTCRSSLSESSIONINT_MAGIC, VERR_INVALID_HANDLE);
494
495 Assert((size_t)(int)cbToWrite == cbToWrite);
496 Assert(cbToWrite != 0 /* undefined behavior if zero */);
497
498 int cbActual = SSL_write(pThis->pSsl, pvBuf, (int)cbToWrite);
499 if (cbActual > 0)
500 return cbActual;
501 if (BIO_should_retry(pThis->pBio))
502 return VERR_TRY_AGAIN;
503 return VERR_WRITE_ERROR; /** @todo better status codes. */
504}
505
506#endif /* IPRT_WITH_OPENSSL */
507
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette